Skip to content

Commit 1a1da88

Browse files
author
Jacob Struzik
committed
Merge pull request #5 from Rican7/bugfix/breaking-spec-for-negotiationmessage-encoding
Bugfix - Negotation message payload offset zero values
2 parents 38082f9 + b0a6938 commit 1a1da88

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)