Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
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-cw
Commits
9ea95f41
Commit
9ea95f41
authored
Sep 04, 2013
by
Hans Leidekker
Committed by
Alexandre Julliard
Sep 05, 2013
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
rpcrt4: Add support for NTLM and Negotiate.
parent
a8d87afe
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
472 additions
and
78 deletions
+472
-78
rpc_transport.c
dlls/rpcrt4/rpc_transport.c
+472
-78
No files found.
dlls/rpcrt4/rpc_transport.c
View file @
9ea95f41
...
@@ -101,6 +101,8 @@
...
@@ -101,6 +101,8 @@
#define DEFAULT_NCACN_HTTP_TIMEOUT (60 * 1000)
#define DEFAULT_NCACN_HTTP_TIMEOUT (60 * 1000)
#define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
WINE_DEFAULT_DEBUG_CHANNEL
(
rpc
);
WINE_DEFAULT_DEBUG_CHANNEL
(
rpc
);
static
RPC_STATUS
RPCRT4_SpawnConnection
(
RpcConnection
**
Connection
,
RpcConnection
*
OldConnection
);
static
RPC_STATUS
RPCRT4_SpawnConnection
(
RpcConnection
**
Connection
,
RpcConnection
*
OldConnection
);
...
@@ -1907,6 +1909,19 @@ static RPC_STATUS wait_async_request(RpcHttpAsyncData *async_data, BOOL call_ret
...
@@ -1907,6 +1909,19 @@ static RPC_STATUS wait_async_request(RpcHttpAsyncData *async_data, BOOL call_ret
return
RPC_S_OK
;
return
RPC_S_OK
;
}
}
struct
authinfo
{
DWORD
scheme
;
CredHandle
cred
;
CtxtHandle
ctx
;
TimeStamp
exp
;
ULONG
attr
;
ULONG
max_token
;
char
*
data
;
unsigned
int
data_len
;
BOOL
finished
;
/* finished authenticating */
};
typedef
struct
_RpcConnection_http
typedef
struct
_RpcConnection_http
{
{
RpcConnection
common
;
RpcConnection
common
;
...
@@ -1914,6 +1929,7 @@ typedef struct _RpcConnection_http
...
@@ -1914,6 +1929,7 @@ typedef struct _RpcConnection_http
HINTERNET
session
;
HINTERNET
session
;
HINTERNET
in_request
;
HINTERNET
in_request
;
HINTERNET
out_request
;
HINTERNET
out_request
;
WCHAR
*
servername
;
HANDLE
timer_cancelled
;
HANDLE
timer_cancelled
;
HANDLE
cancel_event
;
HANDLE
cancel_event
;
DWORD
last_sent_time
;
DWORD
last_sent_time
;
...
@@ -2174,14 +2190,14 @@ static RPC_STATUS rpcrt4_http_internet_connect(RpcConnection_http *httpc)
...
@@ -2174,14 +2190,14 @@ static RPC_STATUS rpcrt4_http_internet_connect(RpcConnection_http *httpc)
HeapFree
(
GetProcessHeap
(),
0
,
password
);
HeapFree
(
GetProcessHeap
(),
0
,
password
);
HeapFree
(
GetProcessHeap
(),
0
,
user
);
HeapFree
(
GetProcessHeap
(),
0
,
user
);
HeapFree
(
GetProcessHeap
(),
0
,
proxy
);
HeapFree
(
GetProcessHeap
(),
0
,
proxy
);
HeapFree
(
GetProcessHeap
(),
0
,
servername
);
if
(
!
httpc
->
session
)
if
(
!
httpc
->
session
)
{
{
ERR
(
"InternetConnectW failed with error %d
\n
"
,
GetLastError
());
ERR
(
"InternetConnectW failed with error %d
\n
"
,
GetLastError
());
HeapFree
(
GetProcessHeap
(),
0
,
servername
);
return
RPC_S_SERVER_UNAVAILABLE
;
return
RPC_S_SERVER_UNAVAILABLE
;
}
}
httpc
->
servername
=
servername
;
return
RPC_S_OK
;
return
RPC_S_OK
;
}
}
...
@@ -2192,6 +2208,8 @@ static RPC_STATUS send_echo_request(HINTERNET req, RpcHttpAsyncData *async_data,
...
@@ -2192,6 +2208,8 @@ static RPC_STATUS send_echo_request(HINTERNET req, RpcHttpAsyncData *async_data,
BOOL
ret
;
BOOL
ret
;
RPC_STATUS
status
;
RPC_STATUS
status
;
TRACE
(
"sending echo request to server
\n
"
);
prepare_async_request
(
async_data
);
prepare_async_request
(
async_data
);
ret
=
HttpSendRequestW
(
req
,
NULL
,
0
,
NULL
,
0
);
ret
=
HttpSendRequestW
(
req
,
NULL
,
0
,
NULL
,
0
);
status
=
wait_async_request
(
async_data
,
ret
,
cancel_event
);
status
=
wait_async_request
(
async_data
,
ret
,
cancel_event
);
...
@@ -2208,9 +2226,8 @@ static RPC_STATUS send_echo_request(HINTERNET req, RpcHttpAsyncData *async_data,
...
@@ -2208,9 +2226,8 @@ static RPC_STATUS send_echo_request(HINTERNET req, RpcHttpAsyncData *async_data,
/* prepare the in pipe for use by RPC packets */
/* prepare the in pipe for use by RPC packets */
static
RPC_STATUS
rpcrt4_http_prepare_in_pipe
(
HINTERNET
in_request
,
RpcHttpAsyncData
*
async_data
,
HANDLE
cancel_event
,
static
RPC_STATUS
rpcrt4_http_prepare_in_pipe
(
HINTERNET
in_request
,
RpcHttpAsyncData
*
async_data
,
HANDLE
cancel_event
,
const
UUID
*
connection_uuid
,
const
UUID
*
connection_uuid
,
const
UUID
*
in_pipe_uuid
,
const
UUID
*
in_pipe_uuid
,
const
UUID
*
association_uuid
,
BOOL
authorized
)
const
UUID
*
association_uuid
)
{
{
BOOL
ret
;
BOOL
ret
;
RPC_STATUS
status
;
RPC_STATUS
status
;
...
@@ -2218,10 +2235,12 @@ static RPC_STATUS rpcrt4_http_prepare_in_pipe(HINTERNET in_request, RpcHttpAsync
...
@@ -2218,10 +2235,12 @@ static RPC_STATUS rpcrt4_http_prepare_in_pipe(HINTERNET in_request, RpcHttpAsync
INTERNET_BUFFERSW
buffers_in
;
INTERNET_BUFFERSW
buffers_in
;
DWORD
bytes_written
;
DWORD
bytes_written
;
/* prepare in pipe */
if
(
!
authorized
)
status
=
send_echo_request
(
in_request
,
async_data
,
cancel_event
);
{
if
(
status
!=
RPC_S_OK
)
return
status
;
/* ask wininet to authorize, if necessary */
status
=
send_echo_request
(
in_request
,
async_data
,
cancel_event
);
if
(
status
!=
RPC_S_OK
)
return
status
;
}
memset
(
&
buffers_in
,
0
,
sizeof
(
buffers_in
));
memset
(
&
buffers_in
,
0
,
sizeof
(
buffers_in
));
buffers_in
.
dwStructSize
=
sizeof
(
buffers_in
);
buffers_in
.
dwStructSize
=
sizeof
(
buffers_in
);
/* FIXME: get this from the registry */
/* FIXME: get this from the registry */
...
@@ -2291,12 +2310,10 @@ static RPC_STATUS rpcrt4_http_read_http_packet(HINTERNET request, RpcPktHdr *hdr
...
@@ -2291,12 +2310,10 @@ static RPC_STATUS rpcrt4_http_read_http_packet(HINTERNET request, RpcPktHdr *hdr
}
}
/* prepare the out pipe for use by RPC packets */
/* prepare the out pipe for use by RPC packets */
static
RPC_STATUS
rpcrt4_http_prepare_out_pipe
(
HINTERNET
out_request
,
static
RPC_STATUS
rpcrt4_http_prepare_out_pipe
(
HINTERNET
out_request
,
RpcHttpAsyncData
*
async_data
,
RpcHttpAsyncData
*
async_data
,
HANDLE
cancel_event
,
const
UUID
*
connection_uuid
,
HANDLE
cancel_event
,
const
UUID
*
out_pipe_uuid
,
ULONG
*
flow_control_increment
,
const
UUID
*
connection_uuid
,
BOOL
authorized
)
const
UUID
*
out_pipe_uuid
,
ULONG
*
flow_control_increment
)
{
{
BOOL
ret
;
BOOL
ret
;
RPC_STATUS
status
;
RPC_STATUS
status
;
...
@@ -2304,13 +2321,22 @@ static RPC_STATUS rpcrt4_http_prepare_out_pipe(HINTERNET out_request,
...
@@ -2304,13 +2321,22 @@ static RPC_STATUS rpcrt4_http_prepare_out_pipe(HINTERNET out_request,
BYTE
*
data_from_server
;
BYTE
*
data_from_server
;
RpcPktHdr
pkt_from_server
;
RpcPktHdr
pkt_from_server
;
ULONG
field1
,
field3
;
ULONG
field1
,
field3
;
DWORD
bytes_read
;
BYTE
buf
[
20
];
status
=
send_echo_request
(
out_request
,
async_data
,
cancel_event
);
if
(
!
authorized
)
if
(
status
!=
RPC_S_OK
)
return
status
;
{
/* ask wininet to authorize, if necessary */
status
=
send_echo_request
(
out_request
,
async_data
,
cancel_event
);
if
(
status
!=
RPC_S_OK
)
return
status
;
}
else
InternetReadFile
(
out_request
,
buf
,
sizeof
(
buf
),
&
bytes_read
);
hdr
=
RPCRT4_BuildHttpConnectHeader
(
TRUE
,
connection_uuid
,
out_pipe_uuid
,
NULL
);
hdr
=
RPCRT4_BuildHttpConnectHeader
(
TRUE
,
connection_uuid
,
out_pipe_uuid
,
NULL
);
if
(
!
hdr
)
return
RPC_S_OUT_OF_RESOURCES
;
if
(
!
hdr
)
return
RPC_S_OUT_OF_RESOURCES
;
TRACE
(
"sending HTTP connect header to server
\n
"
);
prepare_async_request
(
async_data
);
prepare_async_request
(
async_data
);
ret
=
HttpSendRequestW
(
out_request
,
NULL
,
0
,
hdr
,
hdr
->
common
.
frag_len
);
ret
=
HttpSendRequestW
(
out_request
,
NULL
,
0
,
hdr
,
hdr
->
common
.
frag_len
);
status
=
wait_async_request
(
async_data
,
ret
,
cancel_event
);
status
=
wait_async_request
(
async_data
,
ret
,
cancel_event
);
...
@@ -2395,55 +2421,390 @@ static UINT encode_base64(const char *bin, unsigned int len, WCHAR *base64)
...
@@ -2395,55 +2421,390 @@ static UINT encode_base64(const char *bin, unsigned int len, WCHAR *base64)
return
i
;
return
i
;
}
}
static
RPC_STATUS
insert_authorization_header
(
HINTERNET
request
,
RpcQualityOfService
*
qos
)
static
inline
char
decode_char
(
WCHAR
c
)
{
{
static
const
WCHAR
basicW
[]
=
if
(
c
>=
'A'
&&
c
<=
'Z'
)
return
c
-
'A'
;
{
'A'
,
'u'
,
't'
,
'h'
,
'o'
,
'r'
,
'i'
,
'z'
,
'a'
,
't'
,
'i'
,
'o'
,
'n'
,
':'
,
' '
,
'B'
,
'a'
,
's'
,
'i'
,
'c'
,
' '
};
if
(
c
>=
'a'
&&
c
<=
'z'
)
return
c
-
'a'
+
26
;
RPC_HTTP_TRANSPORT_CREDENTIALS_W
*
creds
;
if
(
c
>=
'0'
&&
c
<=
'9'
)
return
c
-
'0'
+
52
;
SEC_WINNT_AUTH_IDENTITY_W
*
id
;
if
(
c
==
'+'
)
return
62
;
int
len
,
datalen
,
userlen
,
passlen
;
if
(
c
==
'/'
)
return
63
;
WCHAR
*
header
,
*
ptr
;
return
64
;
char
*
data
;
}
static
unsigned
int
decode_base64
(
const
WCHAR
*
base64
,
unsigned
int
len
,
char
*
buf
)
{
unsigned
int
i
=
0
;
char
c0
,
c1
,
c2
,
c3
;
const
WCHAR
*
p
=
base64
;
while
(
len
>
4
)
{
if
((
c0
=
decode_char
(
p
[
0
]
))
>
63
)
return
0
;
if
((
c1
=
decode_char
(
p
[
1
]
))
>
63
)
return
0
;
if
((
c2
=
decode_char
(
p
[
2
]
))
>
63
)
return
0
;
if
((
c3
=
decode_char
(
p
[
3
]
))
>
63
)
return
0
;
if
(
buf
)
{
buf
[
i
+
0
]
=
(
c0
<<
2
)
|
(
c1
>>
4
);
buf
[
i
+
1
]
=
(
c1
<<
4
)
|
(
c2
>>
2
);
buf
[
i
+
2
]
=
(
c2
<<
6
)
|
c3
;
}
len
-=
4
;
i
+=
3
;
p
+=
4
;
}
if
(
p
[
2
]
==
'='
)
{
if
((
c0
=
decode_char
(
p
[
0
]
))
>
63
)
return
0
;
if
((
c1
=
decode_char
(
p
[
1
]
))
>
63
)
return
0
;
if
(
buf
)
buf
[
i
]
=
(
c0
<<
2
)
|
(
c1
>>
4
);
i
++
;
}
else
if
(
p
[
3
]
==
'='
)
{
if
((
c0
=
decode_char
(
p
[
0
]
))
>
63
)
return
0
;
if
((
c1
=
decode_char
(
p
[
1
]
))
>
63
)
return
0
;
if
((
c2
=
decode_char
(
p
[
2
]
))
>
63
)
return
0
;
if
(
buf
)
{
buf
[
i
+
0
]
=
(
c0
<<
2
)
|
(
c1
>>
4
);
buf
[
i
+
1
]
=
(
c1
<<
4
)
|
(
c2
>>
2
);
}
i
+=
2
;
}
else
{
if
((
c0
=
decode_char
(
p
[
0
]
))
>
63
)
return
0
;
if
((
c1
=
decode_char
(
p
[
1
]
))
>
63
)
return
0
;
if
((
c2
=
decode_char
(
p
[
2
]
))
>
63
)
return
0
;
if
((
c3
=
decode_char
(
p
[
3
]
))
>
63
)
return
0
;
if
(
buf
)
{
buf
[
i
+
0
]
=
(
c0
<<
2
)
|
(
c1
>>
4
);
buf
[
i
+
1
]
=
(
c1
<<
4
)
|
(
c2
>>
2
);
buf
[
i
+
2
]
=
(
c2
<<
6
)
|
c3
;
}
i
+=
3
;
}
return
i
;
}
static
struct
authinfo
*
alloc_authinfo
(
void
)
{
struct
authinfo
*
ret
;
if
(
!
(
ret
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
*
ret
)
)))
return
NULL
;
SecInvalidateHandle
(
&
ret
->
cred
);
SecInvalidateHandle
(
&
ret
->
ctx
);
memset
(
&
ret
->
exp
,
0
,
sizeof
(
ret
->
exp
));
ret
->
scheme
=
0
;
ret
->
attr
=
0
;
ret
->
max_token
=
0
;
ret
->
data
=
NULL
;
ret
->
data_len
=
0
;
ret
->
finished
=
FALSE
;
return
ret
;
}
static
void
destroy_authinfo
(
struct
authinfo
*
info
)
{
if
(
!
info
)
return
;
if
(
SecIsValidHandle
(
&
info
->
ctx
))
DeleteSecurityContext
(
&
info
->
ctx
);
if
(
SecIsValidHandle
(
&
info
->
cred
))
FreeCredentialsHandle
(
&
info
->
cred
);
HeapFree
(
GetProcessHeap
(),
0
,
info
->
data
);
HeapFree
(
GetProcessHeap
(),
0
,
info
);
}
static
const
WCHAR
basicW
[]
=
{
'B'
,
'a'
,
's'
,
'i'
,
'c'
,
0
};
static
const
WCHAR
ntlmW
[]
=
{
'N'
,
'T'
,
'L'
,
'M'
,
0
};
static
const
WCHAR
passportW
[]
=
{
'P'
,
'a'
,
's'
,
's'
,
'p'
,
'o'
,
'r'
,
't'
,
0
};
static
const
WCHAR
digestW
[]
=
{
'D'
,
'i'
,
'g'
,
'e'
,
's'
,
't'
,
0
};
static
const
WCHAR
negotiateW
[]
=
{
'N'
,
'e'
,
'g'
,
'o'
,
't'
,
'i'
,
'a'
,
't'
,
'e'
,
0
};
static
const
struct
{
const
WCHAR
*
str
;
unsigned
int
len
;
DWORD
scheme
;
}
auth_schemes
[]
=
{
{
basicW
,
ARRAYSIZE
(
basicW
)
-
1
,
RPC_C_HTTP_AUTHN_SCHEME_BASIC
},
{
ntlmW
,
ARRAYSIZE
(
ntlmW
)
-
1
,
RPC_C_HTTP_AUTHN_SCHEME_NTLM
},
{
passportW
,
ARRAYSIZE
(
passportW
)
-
1
,
RPC_C_HTTP_AUTHN_SCHEME_PASSPORT
},
{
digestW
,
ARRAYSIZE
(
digestW
)
-
1
,
RPC_C_HTTP_AUTHN_SCHEME_DIGEST
},
{
negotiateW
,
ARRAYSIZE
(
negotiateW
)
-
1
,
RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE
}
};
static
const
unsigned
int
num_auth_schemes
=
sizeof
(
auth_schemes
)
/
sizeof
(
auth_schemes
[
0
]);
static
DWORD
auth_scheme_from_header
(
const
WCHAR
*
header
)
{
unsigned
int
i
;
for
(
i
=
0
;
i
<
num_auth_schemes
;
i
++
)
{
if
(
!
strncmpiW
(
header
,
auth_schemes
[
i
].
str
,
auth_schemes
[
i
].
len
)
&&
(
header
[
auth_schemes
[
i
].
len
]
==
' '
||
!
header
[
auth_schemes
[
i
].
len
]))
return
auth_schemes
[
i
].
scheme
;
}
return
0
;
}
static
BOOL
get_authvalue
(
HINTERNET
request
,
DWORD
scheme
,
WCHAR
*
buffer
,
DWORD
buflen
)
{
DWORD
len
,
index
=
0
;
for
(;;)
{
len
=
buflen
;
if
(
!
HttpQueryInfoW
(
request
,
HTTP_QUERY_WWW_AUTHENTICATE
,
buffer
,
&
len
,
&
index
))
return
FALSE
;
if
(
auth_scheme_from_header
(
buffer
)
==
scheme
)
break
;
}
return
TRUE
;
}
static
RPC_STATUS
do_authorization
(
HINTERNET
request
,
SEC_WCHAR
*
servername
,
const
RPC_HTTP_TRANSPORT_CREDENTIALS_W
*
creds
,
struct
authinfo
**
auth_ptr
)
{
struct
authinfo
*
info
=
*
auth_ptr
;
SEC_WINNT_AUTH_IDENTITY_W
*
id
=
creds
->
TransportCredentials
;
RPC_STATUS
status
=
RPC_S_SERVER_UNAVAILABLE
;
RPC_STATUS
status
=
RPC_S_SERVER_UNAVAILABLE
;
if
(
!
qos
||
qos
->
qos
->
AdditionalSecurityInfoType
!=
RPC_C_AUTHN_INFO_TYPE_HTTP
)
if
((
!
info
&&
!
(
info
=
alloc_authinfo
())))
return
RPC_S_SERVER_UNAVAILABLE
;
return
RPC_S_OK
;
creds
=
qos
->
qos
->
u
.
HttpCredentials
;
switch
(
creds
->
AuthnSchemes
[
0
])
if
(
creds
->
AuthenticationTarget
!=
RPC_C_HTTP_AUTHN_TARGET_SERVER
||
!
creds
->
NumberOfAuthnSchemes
)
{
return
RPC_S_OK
;
case
RPC_C_HTTP_AUTHN_SCHEME_BASIC
:
{
int
userlen
=
WideCharToMultiByte
(
CP_UTF8
,
0
,
id
->
User
,
id
->
UserLength
,
NULL
,
0
,
NULL
,
NULL
);
int
passlen
=
WideCharToMultiByte
(
CP_UTF8
,
0
,
id
->
Password
,
id
->
PasswordLength
,
NULL
,
0
,
NULL
,
NULL
);
if
(
creds
->
AuthnSchemes
[
0
]
!=
RPC_C_HTTP_AUTHN_SCHEME_BASIC
)
info
->
data_len
=
userlen
+
passlen
+
1
;
if
(
!
(
info
->
data
=
HeapAlloc
(
GetProcessHeap
(),
0
,
info
->
data_len
)))
{
status
=
RPC_S_OUT_OF_MEMORY
;
break
;
}
WideCharToMultiByte
(
CP_UTF8
,
0
,
id
->
User
,
id
->
UserLength
,
info
->
data
,
userlen
,
NULL
,
NULL
);
info
->
data
[
userlen
]
=
':'
;
WideCharToMultiByte
(
CP_UTF8
,
0
,
id
->
Password
,
id
->
PasswordLength
,
info
->
data
+
userlen
+
1
,
passlen
,
NULL
,
NULL
);
info
->
scheme
=
RPC_C_HTTP_AUTHN_SCHEME_BASIC
;
info
->
finished
=
TRUE
;
status
=
RPC_S_OK
;
break
;
}
case
RPC_C_HTTP_AUTHN_SCHEME_NTLM
:
case
RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE
:
{
{
static
SEC_WCHAR
ntlmW
[]
=
{
'N'
,
'T'
,
'L'
,
'M'
,
0
},
negotiateW
[]
=
{
'N'
,
'e'
,
'g'
,
'o'
,
't'
,
'i'
,
'a'
,
't'
,
'e'
,
0
};
SECURITY_STATUS
ret
;
SecBufferDesc
out_desc
,
in_desc
;
SecBuffer
out
,
in
;
ULONG
flags
=
ISC_REQ_CONNECTION
|
ISC_REQ_USE_DCE_STYLE
|
ISC_REQ_MUTUAL_AUTH
|
ISC_REQ_DELEGATE
;
SEC_WCHAR
*
scheme
;
int
scheme_len
;
const
WCHAR
*
p
;
WCHAR
auth_value
[
2048
];
DWORD
size
=
sizeof
(
auth_value
);
BOOL
first
=
FALSE
;
if
(
creds
->
AuthnSchemes
[
0
]
==
RPC_C_HTTP_AUTHN_SCHEME_NTLM
)
scheme
=
ntlmW
;
else
scheme
=
negotiateW
;
scheme_len
=
strlenW
(
scheme
);
if
(
!*
auth_ptr
)
{
TimeStamp
exp
;
SecPkgInfoW
*
pkg_info
;
ret
=
AcquireCredentialsHandleW
(
NULL
,
scheme
,
SECPKG_CRED_OUTBOUND
,
NULL
,
id
,
NULL
,
NULL
,
&
info
->
cred
,
&
exp
);
if
(
ret
!=
SEC_E_OK
)
break
;
ret
=
QuerySecurityPackageInfoW
(
scheme
,
&
pkg_info
);
if
(
ret
!=
SEC_E_OK
)
break
;
info
->
max_token
=
pkg_info
->
cbMaxToken
;
FreeContextBuffer
(
pkg_info
);
first
=
TRUE
;
}
else
{
if
(
info
->
finished
||
!
get_authvalue
(
request
,
creds
->
AuthnSchemes
[
0
],
auth_value
,
size
))
break
;
if
(
auth_scheme_from_header
(
auth_value
)
!=
info
->
scheme
)
{
ERR
(
"authentication scheme changed
\n
"
);
break
;
}
}
in
.
BufferType
=
SECBUFFER_TOKEN
;
in
.
cbBuffer
=
0
;
in
.
pvBuffer
=
NULL
;
in_desc
.
ulVersion
=
0
;
in_desc
.
cBuffers
=
1
;
in_desc
.
pBuffers
=
&
in
;
p
=
auth_value
+
scheme_len
;
if
(
*
p
==
' '
)
{
int
len
=
strlenW
(
++
p
);
in
.
cbBuffer
=
decode_base64
(
p
,
len
,
NULL
);
if
(
!
(
in
.
pvBuffer
=
HeapAlloc
(
GetProcessHeap
(),
0
,
in
.
cbBuffer
)))
break
;
decode_base64
(
p
,
len
,
in
.
pvBuffer
);
}
out
.
BufferType
=
SECBUFFER_TOKEN
;
out
.
cbBuffer
=
info
->
max_token
;
if
(
!
(
out
.
pvBuffer
=
HeapAlloc
(
GetProcessHeap
(),
0
,
out
.
cbBuffer
)))
{
HeapFree
(
GetProcessHeap
(),
0
,
in
.
pvBuffer
);
break
;
}
out_desc
.
ulVersion
=
0
;
out_desc
.
cBuffers
=
1
;
out_desc
.
pBuffers
=
&
out
;
ret
=
InitializeSecurityContextW
(
first
?
&
info
->
cred
:
NULL
,
first
?
NULL
:
&
info
->
ctx
,
first
?
servername
:
NULL
,
flags
,
0
,
SECURITY_NETWORK_DREP
,
in
.
pvBuffer
?
&
in_desc
:
NULL
,
0
,
&
info
->
ctx
,
&
out_desc
,
&
info
->
attr
,
&
info
->
exp
);
HeapFree
(
GetProcessHeap
(),
0
,
in
.
pvBuffer
);
if
(
ret
==
SEC_E_OK
)
{
HeapFree
(
GetProcessHeap
(),
0
,
info
->
data
);
info
->
data
=
out
.
pvBuffer
;
info
->
data_len
=
out
.
cbBuffer
;
info
->
finished
=
TRUE
;
TRACE
(
"sending last auth packet
\n
"
);
status
=
RPC_S_OK
;
}
else
if
(
ret
==
SEC_I_CONTINUE_NEEDED
)
{
HeapFree
(
GetProcessHeap
(),
0
,
info
->
data
);
info
->
data
=
out
.
pvBuffer
;
info
->
data_len
=
out
.
cbBuffer
;
TRACE
(
"sending next auth packet
\n
"
);
status
=
RPC_S_OK
;
}
else
{
ERR
(
"InitializeSecurityContextW failed with error 0x%08x
\n
"
,
ret
);
HeapFree
(
GetProcessHeap
(),
0
,
out
.
pvBuffer
);
break
;
}
info
->
scheme
=
creds
->
AuthnSchemes
[
0
];
break
;
}
default:
FIXME
(
"scheme %u not supported
\n
"
,
creds
->
AuthnSchemes
[
0
]);
FIXME
(
"scheme %u not supported
\n
"
,
creds
->
AuthnSchemes
[
0
]);
return
RPC_S_OK
;
break
;
}
}
id
=
creds
->
TransportCredentials
;
if
(
!
id
->
User
||
!
id
->
Password
)
return
RPC_S_OK
;
userlen
=
WideCharToMultiByte
(
CP_UTF8
,
0
,
id
->
User
,
id
->
UserLength
,
NULL
,
0
,
NULL
,
NULL
);
if
(
status
!=
RPC_S_OK
)
passlen
=
WideCharToMultiByte
(
CP_UTF8
,
0
,
id
->
Password
,
id
->
PasswordLength
,
NULL
,
0
,
NULL
,
NULL
);
{
destroy_authinfo
(
info
);
datalen
=
userlen
+
passlen
+
1
;
*
auth_ptr
=
NULL
;
if
(
!
(
data
=
HeapAlloc
(
GetProcessHeap
(),
0
,
datalen
)))
return
RPC_S_OUT_OF_MEMORY
;
return
status
;
}
*
auth_ptr
=
info
;
return
RPC_S_OK
;
}
WideCharToMultiByte
(
CP_UTF8
,
0
,
id
->
User
,
id
->
UserLength
,
data
,
userlen
,
NULL
,
NULL
);
static
RPC_STATUS
insert_authorization_header
(
HINTERNET
request
,
ULONG
scheme
,
char
*
data
,
int
data_len
)
data
[
userlen
]
=
':'
;
{
WideCharToMultiByte
(
CP_UTF8
,
0
,
id
->
Password
,
id
->
PasswordLength
,
data
+
userlen
+
1
,
passlen
,
NULL
,
NULL
);
static
const
WCHAR
authW
[]
=
{
'A'
,
'u'
,
't'
,
'h'
,
'o'
,
'r'
,
'i'
,
'z'
,
'a'
,
't'
,
'i'
,
'o'
,
'n'
,
':'
,
' '
};
static
const
WCHAR
basicW
[]
=
{
'B'
,
'a'
,
's'
,
'i'
,
'c'
,
' '
};
static
const
WCHAR
negotiateW
[]
=
{
'N'
,
'e'
,
'g'
,
'o'
,
't'
,
'i'
,
'a'
,
't'
,
'e'
,
' '
};
static
const
WCHAR
ntlmW
[]
=
{
'N'
,
'T'
,
'L'
,
'M'
,
' '
};
int
scheme_len
,
auth_len
=
sizeof
(
authW
)
/
sizeof
(
authW
[
0
]),
len
=
((
data_len
+
2
)
*
4
)
/
3
;
const
WCHAR
*
scheme_str
;
WCHAR
*
header
,
*
ptr
;
RPC_STATUS
status
=
RPC_S_SERVER_UNAVAILABLE
;
len
=
((
datalen
+
2
)
*
4
)
/
3
;
switch
(
scheme
)
if
((
header
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
basicW
)
+
(
len
+
2
)
*
sizeof
(
WCHAR
))))
{
{
memcpy
(
header
,
basicW
,
sizeof
(
basicW
));
case
RPC_C_HTTP_AUTHN_SCHEME_BASIC
:
ptr
=
header
+
sizeof
(
basicW
)
/
sizeof
(
basicW
[
0
]);
scheme_str
=
basicW
;
len
=
encode_base64
(
data
,
datalen
,
ptr
);
scheme_len
=
sizeof
(
basicW
)
/
sizeof
(
basicW
[
0
]);
break
;
case
RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE
:
scheme_str
=
negotiateW
;
scheme_len
=
sizeof
(
negotiateW
)
/
sizeof
(
negotiateW
[
0
]);
break
;
case
RPC_C_HTTP_AUTHN_SCHEME_NTLM
:
scheme_str
=
ntlmW
;
scheme_len
=
sizeof
(
ntlmW
)
/
sizeof
(
ntlmW
[
0
]);
break
;
default:
ERR
(
"unknown scheme %u
\n
"
,
scheme
);
return
RPC_S_SERVER_UNAVAILABLE
;
}
if
((
header
=
HeapAlloc
(
GetProcessHeap
(),
0
,
(
auth_len
+
scheme_len
+
len
+
2
)
*
sizeof
(
WCHAR
))))
{
memcpy
(
header
,
authW
,
auth_len
*
sizeof
(
WCHAR
));
ptr
=
header
+
auth_len
;
memcpy
(
ptr
,
scheme_str
,
scheme_len
*
sizeof
(
WCHAR
));
ptr
+=
scheme_len
;
len
=
encode_base64
(
data
,
data_len
,
ptr
);
ptr
[
len
++
]
=
'\r'
;
ptr
[
len
++
]
=
'\r'
;
ptr
[
len
++
]
=
'\n'
;
ptr
[
len
++
]
=
'\n'
;
ptr
[
len
]
=
0
;
ptr
[
len
]
=
0
;
if
((
HttpAddRequestHeadersW
(
request
,
header
,
-
1
,
HTTP_ADDREQ_FLAG_ADD_IF_NEW
)))
status
=
RPC_S_OK
;
if
(
HttpAddRequestHeadersW
(
request
,
header
,
-
1
,
HTTP_ADDREQ_FLAG_ADD
|
HTTP_ADDREQ_FLAG_REPLACE
))
status
=
RPC_S_OK
;
HeapFree
(
GetProcessHeap
(),
0
,
header
);
HeapFree
(
GetProcessHeap
(),
0
,
header
);
}
}
HeapFree
(
GetProcessHeap
(),
0
,
data
);
return
status
;
}
static
void
drain_content
(
HINTERNET
request
)
{
DWORD
count
,
len
=
0
,
size
=
sizeof
(
len
);
char
buf
[
2048
];
HttpQueryInfoW
(
request
,
HTTP_QUERY_FLAG_NUMBER
|
HTTP_QUERY_CONTENT_LENGTH
,
&
len
,
&
size
,
NULL
);
if
(
!
len
)
return
;
for
(;;)
{
count
=
min
(
sizeof
(
buf
),
len
);
if
(
!
InternetReadFile
(
request
,
buf
,
count
,
&
count
)
||
!
count
)
return
;
len
-=
count
;
}
}
static
RPC_STATUS
authorize_request
(
RpcConnection_http
*
httpc
,
HINTERNET
request
)
{
static
const
WCHAR
authW
[]
=
{
'A'
,
'u'
,
't'
,
'h'
,
'o'
,
'r'
,
'i'
,
'z'
,
'a'
,
't'
,
'i'
,
'o'
,
'n'
,
':'
,
'\r'
,
'\n'
,
0
};
struct
authinfo
*
info
=
NULL
;
RPC_STATUS
status
;
BOOL
ret
;
for
(;;)
{
status
=
do_authorization
(
request
,
httpc
->
servername
,
httpc
->
common
.
QOS
->
qos
->
u
.
HttpCredentials
,
&
info
);
if
(
status
!=
RPC_S_OK
)
break
;
status
=
insert_authorization_header
(
request
,
info
->
scheme
,
info
->
data
,
info
->
data_len
);
if
(
status
!=
RPC_S_OK
)
break
;
prepare_async_request
(
httpc
->
async_data
);
ret
=
HttpSendRequestW
(
request
,
NULL
,
0
,
NULL
,
0
);
status
=
wait_async_request
(
httpc
->
async_data
,
ret
,
httpc
->
cancel_event
);
if
(
status
!=
RPC_S_OK
||
info
->
finished
)
break
;
status
=
rpcrt4_http_check_response
(
request
);
if
(
status
!=
RPC_S_OK
&&
status
!=
ERROR_ACCESS_DENIED
)
break
;
drain_content
(
request
);
}
HttpAddRequestHeadersW
(
request
,
authW
,
-
1
,
HTTP_ADDREQ_FLAG_REPLACE
);
destroy_authinfo
(
info
);
return
status
;
return
status
;
}
}
...
@@ -2471,6 +2832,31 @@ static RPC_STATUS insert_cookie_header(HINTERNET request, const WCHAR *value)
...
@@ -2471,6 +2832,31 @@ static RPC_STATUS insert_cookie_header(HINTERNET request, const WCHAR *value)
return
status
;
return
status
;
}
}
static
BOOL
has_credentials
(
RpcConnection_http
*
httpc
)
{
RPC_HTTP_TRANSPORT_CREDENTIALS_W
*
creds
;
SEC_WINNT_AUTH_IDENTITY_W
*
id
;
if
(
!
httpc
->
common
.
QOS
||
httpc
->
common
.
QOS
->
qos
->
AdditionalSecurityInfoType
!=
RPC_C_AUTHN_INFO_TYPE_HTTP
)
return
FALSE
;
creds
=
httpc
->
common
.
QOS
->
qos
->
u
.
HttpCredentials
;
if
(
creds
->
AuthenticationTarget
!=
RPC_C_HTTP_AUTHN_TARGET_SERVER
||
!
creds
->
NumberOfAuthnSchemes
)
return
FALSE
;
id
=
creds
->
TransportCredentials
;
if
(
!
id
||
!
id
->
User
||
!
id
->
Password
)
return
FALSE
;
return
TRUE
;
}
static
BOOL
is_secure
(
RpcConnection_http
*
httpc
)
{
return
httpc
->
common
.
QOS
&&
(
httpc
->
common
.
QOS
->
qos
->
AdditionalSecurityInfoType
==
RPC_C_AUTHN_INFO_TYPE_HTTP
)
&&
(
httpc
->
common
.
QOS
->
qos
->
u
.
HttpCredentials
->
Flags
&
RPC_C_HTTP_FLAG_USE_SSL
);
}
static
RPC_STATUS
rpcrt4_ncacn_http_open
(
RpcConnection
*
Connection
)
static
RPC_STATUS
rpcrt4_ncacn_http_open
(
RpcConnection
*
Connection
)
{
{
RpcConnection_http
*
httpc
=
(
RpcConnection_http
*
)
Connection
;
RpcConnection_http
*
httpc
=
(
RpcConnection_http
*
)
Connection
;
...
@@ -2483,7 +2869,7 @@ static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
...
@@ -2483,7 +2869,7 @@ static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
DWORD
flags
;
DWORD
flags
;
WCHAR
*
url
;
WCHAR
*
url
;
RPC_STATUS
status
;
RPC_STATUS
status
;
BOOL
secure
;
BOOL
secure
,
credentials
;
HttpTimerThreadData
*
timer_data
;
HttpTimerThreadData
*
timer_data
;
HANDLE
thread
;
HANDLE
thread
;
...
@@ -2516,13 +2902,13 @@ static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
...
@@ -2516,13 +2902,13 @@ static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
strcatW
(
url
,
wszColon
);
strcatW
(
url
,
wszColon
);
MultiByteToWideChar
(
CP_ACP
,
0
,
Connection
->
Endpoint
,
-
1
,
url
+
strlenW
(
url
),
strlen
(
Connection
->
Endpoint
)
+
1
);
MultiByteToWideChar
(
CP_ACP
,
0
,
Connection
->
Endpoint
,
-
1
,
url
+
strlenW
(
url
),
strlen
(
Connection
->
Endpoint
)
+
1
);
secure
=
httpc
->
common
.
QOS
&&
secure
=
is_secure
(
httpc
);
(
httpc
->
common
.
QOS
->
qos
->
AdditionalSecurityInfoType
==
RPC_C_AUTHN_INFO_TYPE_HTTP
)
&&
credentials
=
has_credentials
(
httpc
);
(
httpc
->
common
.
QOS
->
qos
->
u
.
HttpCredentials
->
Flags
&
RPC_C_HTTP_FLAG_USE_SSL
);
flags
=
INTERNET_FLAG_KEEP_CONNECTION
|
INTERNET_FLAG_PRAGMA_NOCACHE
|
INTERNET_FLAG_NO_CACHE_WRITE
|
flags
=
INTERNET_FLAG_KEEP_CONNECTION
|
INTERNET_FLAG_PRAGMA_NOCACHE
|
INTERNET_FLAG_NO_CACHE_WRITE
|
INTERNET_FLAG_NO_AUTO_REDIRECT
;
INTERNET_FLAG_NO_AUTO_REDIRECT
;
if
(
secure
)
flags
|=
INTERNET_FLAG_SECURE
;
if
(
secure
)
flags
|=
INTERNET_FLAG_SECURE
;
if
(
credentials
)
flags
|=
INTERNET_FLAG_NO_AUTH
;
httpc
->
in_request
=
HttpOpenRequestW
(
httpc
->
session
,
wszVerbIn
,
url
,
NULL
,
NULL
,
wszAcceptTypes
,
httpc
->
in_request
=
HttpOpenRequestW
(
httpc
->
session
,
wszVerbIn
,
url
,
NULL
,
NULL
,
wszAcceptTypes
,
flags
,
(
DWORD_PTR
)
httpc
->
async_data
);
flags
,
(
DWORD_PTR
)
httpc
->
async_data
);
...
@@ -2532,17 +2918,28 @@ static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
...
@@ -2532,17 +2918,28 @@ static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
HeapFree
(
GetProcessHeap
(),
0
,
url
);
HeapFree
(
GetProcessHeap
(),
0
,
url
);
return
RPC_S_SERVER_UNAVAILABLE
;
return
RPC_S_SERVER_UNAVAILABLE
;
}
}
status
=
insert_authorization_header
(
httpc
->
in_request
,
httpc
->
common
.
QOS
);
if
(
status
!=
RPC_S_OK
)
{
HeapFree
(
GetProcessHeap
(),
0
,
url
);
return
status
;
}
status
=
insert_cookie_header
(
httpc
->
in_request
,
Connection
->
CookieAuth
);
status
=
insert_cookie_header
(
httpc
->
in_request
,
Connection
->
CookieAuth
);
if
(
status
!=
RPC_S_OK
)
{
if
(
status
!=
RPC_S_OK
)
{
HeapFree
(
GetProcessHeap
(),
0
,
url
);
HeapFree
(
GetProcessHeap
(),
0
,
url
);
return
status
;
return
status
;
}
}
if
(
credentials
)
{
status
=
authorize_request
(
httpc
,
httpc
->
in_request
);
if
(
status
!=
RPC_S_OK
)
{
HeapFree
(
GetProcessHeap
(),
0
,
url
);
return
status
;
}
status
=
rpcrt4_http_check_response
(
httpc
->
in_request
);
if
(
status
!=
RPC_S_OK
)
{
HeapFree
(
GetProcessHeap
(),
0
,
url
);
return
status
;
}
drain_content
(
httpc
->
in_request
);
}
httpc
->
out_request
=
HttpOpenRequestW
(
httpc
->
session
,
wszVerbOut
,
url
,
NULL
,
NULL
,
wszAcceptTypes
,
httpc
->
out_request
=
HttpOpenRequestW
(
httpc
->
session
,
wszVerbOut
,
url
,
NULL
,
NULL
,
wszAcceptTypes
,
flags
,
(
DWORD_PTR
)
httpc
->
async_data
);
flags
,
(
DWORD_PTR
)
httpc
->
async_data
);
...
@@ -2552,29 +2949,26 @@ static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
...
@@ -2552,29 +2949,26 @@ static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
ERR
(
"HttpOpenRequestW failed with error %d
\n
"
,
GetLastError
());
ERR
(
"HttpOpenRequestW failed with error %d
\n
"
,
GetLastError
());
return
RPC_S_SERVER_UNAVAILABLE
;
return
RPC_S_SERVER_UNAVAILABLE
;
}
}
status
=
insert_authorization_header
(
httpc
->
out_request
,
httpc
->
common
.
QOS
);
if
(
status
!=
RPC_S_OK
)
return
status
;
status
=
insert_cookie_header
(
httpc
->
out_request
,
Connection
->
CookieAuth
);
status
=
insert_cookie_header
(
httpc
->
out_request
,
Connection
->
CookieAuth
);
if
(
status
!=
RPC_S_OK
)
if
(
status
!=
RPC_S_OK
)
return
status
;
return
status
;
status
=
rpcrt4_http_prepare_in_pipe
(
httpc
->
in_request
,
if
(
credentials
)
httpc
->
async_data
,
{
httpc
->
cancel_event
,
status
=
authorize_request
(
httpc
,
httpc
->
out_request
);
&
httpc
->
connection_uuid
,
if
(
status
!=
RPC_S_OK
)
&
httpc
->
in_pipe_uuid
,
return
status
;
&
Connection
->
assoc
->
http_uuid
);
}
status
=
rpcrt4_http_prepare_in_pipe
(
httpc
->
in_request
,
httpc
->
async_data
,
httpc
->
cancel_event
,
&
httpc
->
connection_uuid
,
&
httpc
->
in_pipe_uuid
,
&
Connection
->
assoc
->
http_uuid
,
credentials
);
if
(
status
!=
RPC_S_OK
)
if
(
status
!=
RPC_S_OK
)
return
status
;
return
status
;
status
=
rpcrt4_http_prepare_out_pipe
(
httpc
->
out_request
,
status
=
rpcrt4_http_prepare_out_pipe
(
httpc
->
out_request
,
httpc
->
async_data
,
httpc
->
cancel_event
,
httpc
->
async_data
,
&
httpc
->
connection_uuid
,
&
httpc
->
out_pipe_uuid
,
httpc
->
cancel_event
,
&
httpc
->
flow_control_increment
,
credentials
);
&
httpc
->
connection_uuid
,
&
httpc
->
out_pipe_uuid
,
&
httpc
->
flow_control_increment
);
if
(
status
!=
RPC_S_OK
)
if
(
status
!=
RPC_S_OK
)
return
status
;
return
status
;
...
@@ -2837,6 +3231,8 @@ static int rpcrt4_ncacn_http_close(RpcConnection *Connection)
...
@@ -2837,6 +3231,8 @@ static int rpcrt4_ncacn_http_close(RpcConnection *Connection)
RpcHttpAsyncData_Release
(
httpc
->
async_data
);
RpcHttpAsyncData_Release
(
httpc
->
async_data
);
if
(
httpc
->
cancel_event
)
if
(
httpc
->
cancel_event
)
CloseHandle
(
httpc
->
cancel_event
);
CloseHandle
(
httpc
->
cancel_event
);
HeapFree
(
GetProcessHeap
(),
0
,
httpc
->
servername
);
httpc
->
servername
=
NULL
;
return
0
;
return
0
;
}
}
...
@@ -2994,8 +3390,6 @@ static const struct protseq_ops protseq_list[] =
...
@@ -2994,8 +3390,6 @@ static const struct protseq_ops protseq_list[] =
},
},
};
};
#define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
const
struct
protseq_ops
*
rpcrt4_get_protseq_ops
(
const
char
*
protseq
)
const
struct
protseq_ops
*
rpcrt4_get_protseq_ops
(
const
char
*
protseq
)
{
{
unsigned
int
i
;
unsigned
int
i
;
...
...
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