Skip to content

Commit b0a6938

Browse files
committed
Now breaking spec by sending up zero values for
the payload offsets of the domain name and hostname, due to some NTLM servers expecting a zero offset denotion when the negotiation flags don't include the flags for supplying the domain and workstation meta. This is what cURL does, so it's seemingly safe here. #facepalm - Spec: https://msdn.microsoft.com/en-us/library/cc236641.aspx - "DomainNameBufferOffset field SHOULD be set to the offset from the beginning of the NEGOTIATE_MESSAGE to where the DomainName would be in Payload if it was present." - "WorkstationBufferOffset field SHOULD be set to the offset from the beginning of the NEGOTIATE_MESSAGE to where the WorkstationName would be in Payload if it was present." - cURL forcing a 0 length and offset: https://github.com/bagder/curl/blob/curl-7_46_0/lib/curl_ntlm_msgs.c#L364-L370
1 parent 38082f9 commit b0a6938

1 file changed

Lines changed: 27 additions & 2 deletions

File tree

src/Robin/Ntlm/Message/NegotiateMessageEncoder.php

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,13 @@ public function encode($nt_domain, $client_hostname, $negotiate_flags = null)
9494
// Get our default negotiate flags if none were supplied
9595
$negotiate_flags = (null === $negotiate_flags) ? static::getDefaultNegotiateFlags() : $negotiate_flags;
9696

97+
$nt_domain_supplied = false;
98+
$client_hostname_supplied = false;
99+
97100
if ((NegotiateFlag::NEGOTIATE_OEM_DOMAIN_SUPPLIED & $negotiate_flags)
98101
=== NegotiateFlag::NEGOTIATE_OEM_DOMAIN_SUPPLIED) {
102+
$nt_domain_supplied = true;
103+
99104
$nt_domain = $this->encoding_converter->convert(
100105
strtoupper($nt_domain),
101106
static::OEM_ENCODING
@@ -107,6 +112,8 @@ public function encode($nt_domain, $client_hostname, $negotiate_flags = null)
107112

108113
if ((NegotiateFlag::NEGOTIATE_OEM_WORKSTATION_SUPPLIED & $negotiate_flags)
109114
=== NegotiateFlag::NEGOTIATE_OEM_WORKSTATION_SUPPLIED) {
115+
$client_hostname_supplied = true;
116+
110117
$client_hostname = $this->encoding_converter->convert(
111118
strtoupper($client_hostname),
112119
static::OEM_ENCODING
@@ -121,6 +128,24 @@ public function encode($nt_domain, $client_hostname, $negotiate_flags = null)
121128
$domain_name_length = strlen($nt_domain);
122129
$hostname_length = strlen($client_hostname);
123130

131+
/**
132+
* Determine the payload offsets of the domain name and hostname
133+
*
134+
* The specification says that these offsets should be set to valid
135+
* locations even if the negotation flags don't contain the flags
136+
* denoting their inclusion, however some NTLM servers seem to throw a
137+
* bit of a fit if the offsets are set to non-zero values when the flags
138+
* don't denote their inclusion.
139+
*
140+
* So yea, we're breaking spec here to appease some seemingly old or
141+
* improper implementations. cURL does the same here.
142+
*
143+
* @link https://msdn.microsoft.com/en-us/library/cc236641.aspx
144+
* @link https://github.com/bagder/curl/blob/curl-7_46_0/lib/curl_ntlm_msgs.c#L364-L370
145+
*/
146+
$domain_name_offset = $nt_domain_supplied ? $payload_offset : 0;
147+
$hostname_offset = $client_hostname_supplied ? ($payload_offset + $domain_name_length) : 0;
148+
124149
// Prepare a binary string to be returned
125150
$binary_string = '';
126151

@@ -132,12 +157,12 @@ public function encode($nt_domain, $client_hostname, $negotiate_flags = null)
132157
// Domain name fields: length; length; offset of the domain value from the beginning of the message
133158
$binary_string .= pack('v', $domain_name_length); // 16-bit unsigned little-endian
134159
$binary_string .= pack('v', $domain_name_length); // 16-bit unsigned little-endian
135-
$binary_string .= pack('V', $payload_offset); // 32-bit unsigned little-endian, 1st value in the payload
160+
$binary_string .= pack('V', $domain_name_offset); // 32-bit unsigned little-endian, 1st value in the payload
136161

137162
// Hostname fields: length; length; offset of the hostname value from the beginning of the message
138163
$binary_string .= pack('v', $hostname_length); // 16-bit unsigned little-endian
139164
$binary_string .= pack('v', $hostname_length); // 16-bit unsigned little-endian
140-
$binary_string .= pack('V', $payload_offset + $domain_name_length); // 32-bit unsigned little-endian, 2nd value
165+
$binary_string .= pack('V', $hostname_offset); // 32-bit unsigned little-endian, 2nd value
141166

142167
// NOTE: Omitting the version data here. It's unnecessary.
143168

0 commit comments

Comments
 (0)