/////////////////////////////////////////////////////////////////////////////// // // 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 #include #include #include #include #include #include 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(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); }