windows-nt/Source/XPSP1/NT/net/ias/providers/ntuser/auth/blob.cpp
2020-09-26 16:20:57 +08:00

407 lines
9.9 KiB
C++

///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1998, Microsoft Corp. All rights reserved.
//
// FILE
//
// blob.cpp
//
// SYNOPSIS
//
// Defines the various 'blob' classes.
//
// MODIFICATION HISTORY
//
// 08/24/1998 Original version.
// 10/25/1998 New symbolic constants for ARAP.
// 11/10/1998 Added isLmPresent().
// 01/04/1999 MSChapError::insert takes a PPP error code.
// 01/25/1999 MS-CHAP v2
// 05/04/1999 New reason codes.
// 05/11/1999 Fix RADIUS encryption.
// 05/28/1999 Fix MS-MPPE-Keys format.
// 02/17/2000 Key encryption is now handled by the protocol.
//
///////////////////////////////////////////////////////////////////////////////
#include <ias.h>
#include <sdoias.h>
#include <align.h>
#include <algorithm>
#include <cstdio>
#include <samutil.h>
#include <blob.h>
bool MSChapResponse::isLmPresent() const throw ()
{
const BYTE* p = get().lmResponse + _LM_RESPONSE_LENGTH;
do { } while (--p >= get().lmResponse && *p == 0);
return p >= get().lmResponse;
}
bool MSChapCPW2::isLmPresent() const throw ()
{
// Do we have either an LM response or an LM hash.
if ((get().flags[1] & 0x3) != 0x1) { return true; }
// Now make sure the LM fields are zeroed out.
const BYTE* p = get().oldLmHash +
_ENCRYPTED_LM_OWF_PASSWORD_LENGTH + _LM_RESPONSE_LENGTH;
do { } while (--p >= get().oldLmHash && *p == 0);
return p >= get().oldLmHash;
}
//////////
// Retrieves and assembles an MS-CHAP encrypted password. Returns 'true' if
// the password is present, false otherwise.
//////////
BOOL MSChapEncPW::getEncryptedPassword(
IASRequest& request,
DWORD dwId,
PBYTE buf
)
{
//////////
// Are there any attribute with the desired ID ?
//////////
IASAttributeVectorWithBuffer<8> attrs;
if (attrs.load(request, dwId) == 0)
{
return false;
}
//////////
// Allocate space on the stack for the blobs.
//////////
MSChapEncPW* begin = IAS_STACK_NEW(MSChapEncPW, attrs.size());
MSChapEncPW* end = begin;
//////////
// Convert the attributes to password chunks and determine the total length.
//////////
DWORD length = 0;
IASAttributeVector::iterator i;
for (i = attrs.begin(); i != attrs.end(); ++i, ++end)
{
*end = blob_cast<MSChapEncPW>(i->pAttribute);
length += end->getStringLength();
}
//////////
// Do we have the right length ?
//////////
if (length != _SAMPR_ENCRYPTED_USER_PASSWORD_LENGTH)
{
_com_issue_error(IAS_MALFORMED_REQUEST);
}
//////////
// Sort the chunks ...
//////////
std::sort(begin, end);
//////////
// ... then concatenate the strings into the buffer.
//////////
for ( ; begin != end; ++begin)
{
memcpy(buf, begin->get().string, begin->getStringLength());
buf += begin->getStringLength();
}
return true;
}
void MSChapDomain::insert(
IASRequest& request,
BYTE ident,
PCWSTR domain
)
{
//////////
// Allocate an attribute.
//////////
IASAttribute attr(true);
//////////
// Allocate memory for the blob.
//////////
int len = WideCharToMultiByte(CP_ACP, 0, domain, -1, 0, 0, 0, 0);
Layout* val = (Layout*)CoTaskMemAlloc(len + sizeof(Layout));
if (val == NULL) { _com_issue_error(E_OUTOFMEMORY); }
//////////
// Initialize the blob.
//////////
val->ident = ident;
WideCharToMultiByte(CP_ACP, 0, domain, -1, (PSTR)val->string, len, 0, 0);
//////////
// Initialize the attribute and store.
//////////
attr->dwId = MS_ATTRIBUTE_CHAP_DOMAIN;
attr->Value.itType = IASTYPE_OCTET_STRING;
attr->Value.OctetString.lpValue = (PBYTE)val;
attr->Value.OctetString.dwLength = len + sizeof(Layout) - 1;
attr->dwFlags = IAS_INCLUDE_IN_ACCEPT;
attr.store(request);
}
void MSChapError::insert(
IASRequest& request,
BYTE ident,
DWORD errorCode
)
{
//////////
// Allocate an attribute.
//////////
IASAttribute attr(true);
//////////
// Format the error message.
//////////
CHAR buffer[32];
sprintf(buffer, "E=%lu R=0 V=3", errorCode);
//////////
// Allocate memory for the blob.
//////////
ULONG len = strlen(buffer);
Layout* val = (Layout*)CoTaskMemAlloc(len + sizeof(Layout));
if (val == NULL) { _com_issue_error(E_OUTOFMEMORY); }
//////////
// Initialize the blob.
//////////
val->ident = ident;
memcpy(val->string, buffer, len);
//////////
// Initialize the attribute and store.
//////////
attr->dwId = MS_ATTRIBUTE_CHAP_ERROR;
attr->Value.itType = IASTYPE_OCTET_STRING;
attr->Value.OctetString.lpValue = (PBYTE)val;
attr->Value.OctetString.dwLength = len + sizeof(Layout);
attr->dwFlags = IAS_INCLUDE_IN_REJECT;
attr.store(request);
}
void MSChapMPPEKeys::insert(
IASRequest& request,
PBYTE lmKey,
PBYTE ntKey,
PBYTE challenge
)
{
//////////
// Allocate an attribute.
//////////
IASAttribute attr(true);
//////////
// Allocate memory for the value.
//////////
Layout* val = (Layout*)CoTaskMemAlloc(sizeof(Layout));
if (val == NULL) { _com_issue_error(E_OUTOFMEMORY); }
//////////
// Initialize the blob.
//////////
memcpy(val->lmKey, lmKey, sizeof(val->lmKey));
memcpy(val->ntKey, ntKey, sizeof(val->ntKey));
memcpy(val->challenge, challenge, sizeof(val->challenge));
//////////
// Initialize the attribute and store.
//////////
attr->dwId = MS_ATTRIBUTE_CHAP_MPPE_KEYS;
attr->Value.itType = IASTYPE_OCTET_STRING;
attr->Value.OctetString.lpValue = (PBYTE)val;
attr->Value.OctetString.dwLength = sizeof(Layout);
attr->dwFlags = IAS_INCLUDE_IN_ACCEPT;
attr.store(request);
}
// Convert a number to a hex representation.
inline BYTE num2Digit(BYTE num) throw ()
{
return (num < 10) ? num + '0' : num + ('A' - 10);
}
void MSChap2Success::insert(
IASRequest& request,
BYTE ident,
PBYTE authenticatorResponse
)
{
//////////
// Allocate an attribute.
//////////
IASAttribute attr(true);
//////////
// Allocate memory for the value.
//////////
Layout* val = (Layout*)CoTaskMemAlloc(sizeof(Layout));
if (val == NULL) { _com_issue_error(E_OUTOFMEMORY); }
//////////
// Initialize the blob.
//////////
val->ident = ident;
PBYTE p = val->string;
*p++ = 'S';
*p++ = '=';
for (size_t i = 0; i < 20; ++i)
{
*p++ = num2Digit(authenticatorResponse[i] >> 4);
*p++ = num2Digit(authenticatorResponse[i] & 0xF);
}
//////////
// Initialize the attribute and store.
//////////
attr->dwId = MS_ATTRIBUTE_CHAP2_SUCCESS;
attr->Value.itType = IASTYPE_OCTET_STRING;
attr->Value.OctetString.lpValue = (PBYTE)val;
attr->Value.OctetString.dwLength = sizeof(Layout);
attr->dwFlags = IAS_INCLUDE_IN_ACCEPT;
attr.store(request);
}
void MSMPPEKey::insert(
IASRequest& request,
ULONG keyLength,
PBYTE key,
BOOL isSendKey
)
{
//////////
// Allocate an attribute.
//////////
IASAttribute attr(true);
//////////
// Allocate memory for the value.
//////////
ULONG nbyte = ROUND_UP_COUNT(keyLength + 1, 16) + 2;
Layout* val = (Layout*)CoTaskMemAlloc(nbyte);
if (val == NULL) { _com_issue_error(E_OUTOFMEMORY); }
memset(val, 0, nbyte);
//////////
// Initialize the blob.
//////////
val->keyLength = (BYTE)keyLength;
memcpy(val->key, key, keyLength);
//////////
// Initialize the attribute, encrypt, and store.
//////////
attr->dwId = isSendKey ? MS_ATTRIBUTE_MPPE_SEND_KEY
: MS_ATTRIBUTE_MPPE_RECV_KEY;
attr->Value.itType = IASTYPE_OCTET_STRING;
attr->Value.OctetString.lpValue = (PBYTE)val;
attr->Value.OctetString.dwLength = nbyte;
attr->dwFlags = IAS_INCLUDE_IN_ACCEPT;
attr.store(request);
}
void ArapChallengeResponse::insert(
IASRequest& request,
DWORD NTResponse1,
DWORD NTResponse2
)
{
// Allocate an attribute.
IASAttribute attr(true);
// Pack the fields. These are already in network order.
Layout value;
memcpy(value.ntResponse1, &NTResponse1, 4);
memcpy(value.ntResponse2, &NTResponse2, 4);
// Store the value.
attr.setOctetString(sizeof(value), (const BYTE*)&value);
// Initialize the remaining fields.
attr->dwId = RADIUS_ATTRIBUTE_ARAP_CHALLENGE_RESPONSE;
attr->dwFlags = IAS_INCLUDE_IN_ACCEPT;
// Insert the attribute into the request.
attr.store(request);
}
void ArapFeatures::insert(
IASRequest& request,
DWORD PwdCreationDate,
DWORD PwdExpiryDelta,
DWORD CurrentTime
)
{
// Allocate an attribute.
IASAttribute attr(true);
// Pack the fields.
Layout value;
value.changePasswordAllowed = 1; // Change password always allowed.
value.minPasswordLength = 3; // Arbitrary.
// These are already in network order.
memcpy(value.pwdCreationDate, &PwdCreationDate, 4);
memcpy(value.pwdExpiryDelta, &PwdExpiryDelta, 4);
memcpy(value.currentTime, &CurrentTime, 4);
// Store the value.
attr.setOctetString(sizeof(value), (const BYTE*)&value);
// Initialize the rest of the fields.
attr->dwId = RADIUS_ATTRIBUTE_ARAP_FEATURES;
attr->dwFlags = IAS_INCLUDE_IN_ACCEPT;
// Insert the attribute into the request.
attr.store(request);
}