Why is User-Name AVP truncation in RADIUS packets to 31 characters not considered a bug?

  • 1
  • Question
  • Updated 3 years ago
  • Answered
Just a word of warning and a red flag for those deploying Aerohive APs at the moment with WPA2-Enterprise / 802.1X:

There is an issue whereby HiveOS truncates the User-Name AVPs that it sends in RADIUS packets to 31 characters. This means that a RADIUS server must always use the inner identity to get anything reliably meaningful.

Where eduroam is in use, meaning username@fully.qualified.domain.name is always used as the user name format, things break completely where the length is over 31 characters as the outer identity is used for routing as the EAP is terminated elsewhere and the user is completely unable to log on. (Based on the example user name, username@fully.qualified.domain would be sent which would fail to route.)

We have been told by Aerohive via our reseller, much to our amazement, that resolving this is considered a feature issue and not a bug, and they cannot help us further. My open question to Aerohive here is why on earth is this not considered a bug?

Resolving it is apparently being considered for a future release but with a low priority and a longer time frame. Very frustrating.

We are massively displeased at what we feel is the poor level of customer service here because we are asking, perhaps, a difficult question around an uncomfortable truth that might require effort to resolve.

Unfortunately, we have also hit a bug in Microsoft's NPS server that is combining with this to cause us critical downtime as we are unable to ensure that the domain is valid with a regular expression before processing a login request which would act as a workaround.

We have been told that the underlying cause of the issue is due to Aerohive not implementing CAPWAP in HiveOS to RFC specification as there is no fragmentation support; packets using the protocol in their implementation must be 1500 bytes or less and supporting sending the User-Name completely would require CAPWAP to be able to go over this.

Despite the fact that separation of concerns should, prima facie, apply between RADIUS and CAPWAP, somehow the issue extends to both protocols and we have been told that it will not be fixed for just RADIUS.

Urgh!

Regards to all,

Nick
Photo of Nick Lowe

Nick Lowe, Official Rep

  • 2491 Posts
  • 451 Reply Likes
  • frustrated

Posted 5 years ago

  • 1
Photo of Sarah Banks

Sarah Banks

  • 75 Posts
  • 4 Reply Likes
Hi Nick - offline discussions aside, I wanted to touch base on this thread, and comment. I understand the frustration, and we're already working to lengthen the string, to accommodate the use case of a longer email address, just like the example you'd given above. Thanks for chiming in!
Photo of Nick Lowe

Nick Lowe, Official Rep

  • 2491 Posts
  • 451 Reply Likes
Thanks Sarah, looking forward to seeing this resolved! :)

In the mean time, for any Windows shops being bitten by this in one way or another, I ended up coding a quick audit tool in C# that will flag problematic users.

We used this to identify the impact of the bug in our environment.

Compile and call it with the following...

userenumtool.exe domaincontroller.yourdomain.com yourdomain.com 32

And you will get a list back of all the accounts that will fail.

Nick

namespace UserEnumTool
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;

using Microsoft.Win32.SafeHandles;

internal static class Program
{
internal static void Main(string[] args)
{
if (args == null || args.Length <= 0)
{
Console.WriteLine("Specify the server name to query as the first argument.");
Console.WriteLine("Optionally specify the realm to qualify with as the second argument.");
Console.WriteLine("Optionally specify the minimum length at which to include.");
return;
}

string serverName = args[0];
string realm = null;
if (args.Length >= 2)
{
realm = args[1];
}

int minimumLength = 0;
if (args.Length >= 3)
{
int.TryParse(args[2], NumberStyles.None, CultureInfo.InvariantCulture, out minimumLength);
}

Console.WriteLine("Please wait... Querying " + serverName);
Console.WriteLine();

NetApiBuffer netApiBuffer = null;
int entriesRead;
int totalEntries;
try
{
int result = NativeMethods.NetUserEnum(
serverName,
0,
0,
out netApiBuffer,
0xFFFFFFFFu,
out entriesRead,
out totalEntries,
IntPtr.Zero);
if (result != 0)
{
throw new Win32Exception(result);
}

Type type = typeof(UserInfo0);
int size = Marshal.SizeOf(type);
IntPtr buffer = netApiBuffer.DangerousGetHandle();
SortedDictionary<int, SortedSet<string>> usernamesByLengths = new SortedDictionary<int, SortedSet<string>>();
for (int i = 0; i < entriesRead; i++)
{
UserInfo0 userInfo0 = (UserInfo0)Marshal.PtrToStructure(buffer + (i * size), type);
string username = userInfo0.Name;
if (!(username.StartsWith("$") || username.EndsWith("$")))
{
if (realm != null)
{
username += "@" + realm;
}

int length = username.Length;
if (length >= minimumLength)
{
if (usernamesByLengths.ContainsKey(length))
{
usernamesByLengths[length].Add(username);
}
else
{
usernamesByLengths.Add(length, new SortedSet<string> { username });
}
}
}
}

StringBuilder stringBuilder = new StringBuilder();
foreach (var usernamesByLength in usernamesByLengths)
{
int length = usernamesByLength.Key;
SortedSet<string> usernames = usernamesByLength.Value;
foreach (var username in usernames)
{
stringBuilder.AppendLine(username + " (Length: " + length + ")");
}
}

string output = stringBuilder.ToString();
Console.Write(output);
}
finally
{
if (netApiBuffer != null)
{
netApiBuffer.Dispose();
}
}
}
}

internal sealed class NetApiBuffer : SafeHandleZeroOrMinusOneIsInvalid
{
internal NetApiBuffer()
: base(true)
{
}

protected override bool ReleaseHandle()
{
return NativeMethods.NetApiBufferFree(base.handle) == 0;
}
}

internal static class NativeMethods
{
[DllImport("Netapi32.dll", ExactSpelling = true, CharSet = CharSet.Unicode)]
internal static extern int NetUserEnum(
[In, MarshalAs(UnmanagedType.LPWStr)] string serverName,
[In] int level,
[In] int filter,
[Out] out NetApiBuffer buffer,
[In] uint preferredMaximumLength,
[Out] out int entriesRead,
[Out] out int totalEntries,
[In, Out] IntPtr resumeHandle);

[DllImport("Netapi32.dll", ExactSpelling = true)]
internal static extern int NetApiBufferFree(
[In] IntPtr buffer);
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct UserInfo0
{
[MarshalAs(UnmanagedType.LPWStr)]
private string name;

internal string Name
{
get { return this.name; }
}
}
}
Photo of Mike Kouri

Mike Kouri, Official Rep

  • 1030 Posts
  • 271 Reply Likes
Nick (and anyone else monitoring this thread for a resolution),
Sarah is traveling with limited access to this community or email, or else I would have let her update this.

The fix for this issue that Sarah has been championing has been checked into the code base for the next release of HiveOS.
Photo of Nick Lowe

Nick Lowe, Official Rep

  • 2491 Posts
  • 451 Reply Likes
That's fantastic news, Mike.
Photo of Luke Harris

Luke Harris

  • 265 Posts
  • 18 Reply Likes
Was this issue ever resolved in a more recent release of HM?
Photo of Nick Lowe

Nick Lowe, Official Rep

  • 2491 Posts
  • 451 Reply Likes
Yes, this issue has definitely been resolved. The truncation issue has not been an issue for a long while now in HiveOS.

This thread should really be archived therefore as it now serves no useful purpose, it's stale information.
(Edited)
Photo of Luke Harris

Luke Harris

  • 265 Posts
  • 18 Reply Likes
Thanks for this Nick - initial testing of our eduroam/802.1X deployment has proved positive thus far, I just wanted to confirm  that this issue was now resolved. In which release of Hive OS was this prevalent? and in which revision was it then resolved?
Photo of Nick Lowe

Nick Lowe, Official Rep

  • 2491 Posts
  • 451 Reply Likes
The general release of HiveOS 6.1r2 had remnants of this issue. (A prior fix that it contained did not work with accounting after roaming had taken place, a different type of truncation occurred with the User-Name attribute.) All prior releases were also affected by truncation issues.

I was provided with a revised engineering build of HiveOS 6.1r2 in late September 2013 that fully resolved this.

All subsequent general HiveOS releases, so 6.1r3 and later, have included that full fix.

This means that with up-to-date code on even the oldest 802.11n Aerohive APs, the AP320s and AP340s, this is no longer an issue.
(Edited)