/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2000, Microsoft Corp. All rights reserved. // // FILE // // logresult.cpp // // SYNOPSIS // // Defines the function IASRadiusLogResult. // /////////////////////////////////////////////////////////////////////////////// #include #include #include #include // Dummy attribute ID for the stringized reason code. const DWORD IAS_ATTRIBUTE_REASON_STRING = 0xBADF00D; // An empty string. WCHAR emptyString[1]; // Create a newly-allocated copy of a string. PWSTR copyString(PCWSTR sz) throw () { if (sz) { // Calculate the number of bytes. size_t nbyte = (wcslen(sz) + 1) * sizeof(WCHAR); // Allocate the memory. PVOID p = LocalAlloc(LMEM_FIXED, nbyte); if (p) { // Copy the string and return. return (PWSTR)memcpy(p, sz, nbyte); } } // If anything went wrong, return an empty string. return emptyString; } // Frees a string returned by copyString. void freeString(PWSTR sz) throw () { if (sz != emptyString) { LocalFree(sz); } } // Format an integer value. PWSTR formatInteger(DWORD value) throw () { WCHAR buffer[11], *p = buffer + 10; *p = L'\0'; do { *--p = L'0' + (WCHAR)(value % 10); } while (value /= 10); return copyString(p); } // Format a parameter value. PWSTR formatParameter(DWORD value) throw () { WCHAR buffer[13], *p = buffer + 12; *p = L'\0'; do { *--p = L'0' + (WCHAR)(value % 10); } while (value /= 10); *--p = L'%'; *--p = L'%'; return copyString(p); } // Format the IAS_ATTRIBUTE_PROVIDER_TYPE value. PWSTR formatProviderType(DWORD type) throw () { switch (type) { case IAS_PROVIDER_WINDOWS: return formatParameter(IASP_PROVIDER_WINDOWS); case IAS_PROVIDER_RADIUS_PROXY: return formatParameter(IASP_PROVIDER_RADIUS_PROXY); default: return formatParameter(IASP_NONE); } } // Format the IAS_ATTRIBUTE_AUTHENTICATION_TYPE value. PWSTR formatAuthType(DWORD type) throw () { switch (type) { case IAS_AUTH_PAP: return copyString(L"PAP"); case IAS_AUTH_MD5CHAP: return copyString(L"MD5-CHAP"); case IAS_AUTH_MSCHAP: return copyString(L"MS-CHAPv1"); case IAS_AUTH_MSCHAP2: return copyString(L"MS-CHAPv2"); case IAS_AUTH_EAP: return copyString(L"EAP"); case IAS_AUTH_ARAP: return copyString(L"ARAP"); case IAS_AUTH_NONE: return copyString(L"Unauthenticated"); case IAS_AUTH_CUSTOM: return copyString(L"Extension"); case IAS_AUTH_MSCHAP_CPW: return copyString(L"MS-CHAPv1 CPW"); case IAS_AUTH_MSCHAP2_CPW: return copyString(L"MS-CHAPv2 CPW"); default: return formatInteger(type); } } // Format the NAS-Port-Type value. PWSTR formatPortType(DWORD type) throw () { switch (type) { case 0: return copyString(L"Async"); case 1: return copyString(L"Sync"); case 2: return copyString(L"ISDN Sync"); case 3: return copyString(L"ISDN Async V.120"); case 4: return copyString(L"ISDN Async V.110"); case 5: return copyString(L"Virtual"); case 6: return copyString(L"PIAFS"); case 7: return copyString(L"HDLC Clear Channel"); case 8: return copyString(L"X.25"); case 9: return copyString(L"X.75"); case 10: return copyString(L"G.3 Fax"); case 11: return copyString(L"SDSL"); case 12: return copyString(L"ADSL-CAP"); case 13: return copyString(L"ADSL-DMT"); case 14: return copyString(L"IDSL"); case 15: return copyString(L"Ethernet"); case 16: return copyString(L"xDSL"); case 17: return copyString(L"Cable"); case 18: return copyString(L"Wireless - Other"); case 19: return copyString(L"Wireless - IEEE 802.11"); default: return formatInteger(type); } } PWSTR formatAttribute( IRequest* request, IAttributesRaw* raw, DWORD dwId, DWORD defaultValue ) throw () { // Is this one of the 'special' attributes ? switch (dwId) { case IAS_ATTRIBUTE_REASON_CODE: { LONG reason = 0; request->get_Reason(&reason); return formatInteger(reason); } case IAS_ATTRIBUTE_REASON_STRING: { LONG reason = 0; request->get_Reason(&reason); return formatParameter(reason + 0x1000); } } // Get a single attribute with the give ID. DWORD posCount = 1; ATTRIBUTEPOSITION pos; raw->GetAttributes(&posCount, &pos, 1, &dwId); // If it's not present, use the defaultValue parameter. if (!posCount) { return formatParameter(defaultValue); } // Otherwise, save and release. const IASVALUE& val = pos.pAttribute->Value; IASAttributeRelease(pos.pAttribute); // Format the value. switch (val.itType) { case IASTYPE_ENUM: case IASTYPE_INTEGER: { switch (dwId) { case RADIUS_ATTRIBUTE_NAS_PORT_TYPE: return formatPortType(val.Enumerator); case IAS_ATTRIBUTE_PROVIDER_TYPE: return formatProviderType(val.Enumerator); case IAS_ATTRIBUTE_AUTHENTICATION_TYPE: return formatAuthType(val.Enumerator); // Fall through. } return formatInteger(val.Integer); } case IASTYPE_INET_ADDR: { WCHAR buffer[16]; return copyString(ias_inet_htow(val.InetAddr, buffer)); } case IASTYPE_STRING: { if (val.String.pszWide) { return copyString(val.String.pszWide); } else { USES_CONVERSION; return copyString(A2W(val.String.pszAnsi)); } } case IASTYPE_OCTET_STRING: { return copyString(IAS_OCT2WIDE(val.OctetString)); } } return emptyString; } /////// // An InsertionString definition consists of the attribute ID and a // defaultValue to be used if the attribute isn't present. /////// struct InsertionString { DWORD attrID; DWORD defaultValue; }; // Insertion strings for an Access-Accept. InsertionString ACCEPT_ATTRS[] = { { RADIUS_ATTRIBUTE_USER_NAME, IASP_NOT_PRESENT }, { IAS_ATTRIBUTE_FULLY_QUALIFIED_USER_NAME, IASP_UNDETERMINED }, { RADIUS_ATTRIBUTE_NAS_IP_ADDRESS, IASP_NOT_PRESENT }, { RADIUS_ATTRIBUTE_NAS_IDENTIFIER, IASP_NOT_PRESENT }, { IAS_ATTRIBUTE_CLIENT_NAME, IASP_NOT_PRESENT }, { IAS_ATTRIBUTE_CLIENT_IP_ADDRESS, IASP_NOT_PRESENT }, { RADIUS_ATTRIBUTE_CALLING_STATION_ID, IASP_NOT_PRESENT }, { RADIUS_ATTRIBUTE_NAS_PORT_TYPE, IASP_NOT_PRESENT }, { RADIUS_ATTRIBUTE_NAS_PORT, IASP_NOT_PRESENT }, { IAS_ATTRIBUTE_PROXY_POLICY_NAME, IASP_NONE }, { IAS_ATTRIBUTE_PROVIDER_TYPE, IASP_UNDETERMINED }, { IAS_ATTRIBUTE_REMOTE_SERVER_ADDRESS, IASP_UNDETERMINED }, { IAS_ATTRIBUTE_NP_NAME, IASP_UNDETERMINED }, { IAS_ATTRIBUTE_AUTHENTICATION_TYPE, IASP_UNDETERMINED }, { IAS_ATTRIBUTE_EAP_FRIENDLY_NAME, IASP_UNDETERMINED }, { ATTRIBUTE_UNDEFINED, IASP_UNDETERMINED } }; // Insertion strings for an Access-Reject. InsertionString REJECT_ATTRS[] = { { RADIUS_ATTRIBUTE_USER_NAME, IASP_NOT_PRESENT }, { IAS_ATTRIBUTE_FULLY_QUALIFIED_USER_NAME, IASP_UNDETERMINED }, { RADIUS_ATTRIBUTE_NAS_IP_ADDRESS, IASP_NOT_PRESENT }, { RADIUS_ATTRIBUTE_NAS_IDENTIFIER, IASP_NOT_PRESENT }, { RADIUS_ATTRIBUTE_CALLED_STATION_ID, IASP_NOT_PRESENT }, { RADIUS_ATTRIBUTE_CALLING_STATION_ID, IASP_NOT_PRESENT }, { IAS_ATTRIBUTE_CLIENT_NAME, IASP_NOT_PRESENT }, { IAS_ATTRIBUTE_CLIENT_IP_ADDRESS, IASP_NOT_PRESENT }, { RADIUS_ATTRIBUTE_NAS_PORT_TYPE, IASP_NOT_PRESENT }, { RADIUS_ATTRIBUTE_NAS_PORT, IASP_NOT_PRESENT }, { IAS_ATTRIBUTE_PROXY_POLICY_NAME, IASP_NONE }, { IAS_ATTRIBUTE_PROVIDER_TYPE, IASP_UNDETERMINED }, { IAS_ATTRIBUTE_REMOTE_SERVER_ADDRESS, IASP_UNDETERMINED }, { IAS_ATTRIBUTE_NP_NAME, IASP_UNDETERMINED }, { IAS_ATTRIBUTE_AUTHENTICATION_TYPE, IASP_UNDETERMINED }, { IAS_ATTRIBUTE_EAP_FRIENDLY_NAME, IASP_UNDETERMINED }, { IAS_ATTRIBUTE_REASON_CODE, IASP_UNDETERMINED }, { IAS_ATTRIBUTE_REASON_STRING, IASP_UNDETERMINED }, { ATTRIBUTE_UNDEFINED, IASP_UNDETERMINED } }; // Insertion strings for a discarded request. InsertionString DISCARD_ATTRS[] = { { RADIUS_ATTRIBUTE_USER_NAME, IASP_NOT_PRESENT }, { IAS_ATTRIBUTE_FULLY_QUALIFIED_USER_NAME, IASP_UNDETERMINED }, { RADIUS_ATTRIBUTE_NAS_IP_ADDRESS, IASP_NOT_PRESENT }, { RADIUS_ATTRIBUTE_NAS_IDENTIFIER, IASP_NOT_PRESENT }, { RADIUS_ATTRIBUTE_CALLED_STATION_ID, IASP_NOT_PRESENT }, { RADIUS_ATTRIBUTE_CALLING_STATION_ID, IASP_NOT_PRESENT }, { IAS_ATTRIBUTE_CLIENT_NAME, IASP_NOT_PRESENT }, { IAS_ATTRIBUTE_CLIENT_IP_ADDRESS, IASP_NOT_PRESENT }, { RADIUS_ATTRIBUTE_NAS_PORT_TYPE, IASP_NOT_PRESENT }, { RADIUS_ATTRIBUTE_NAS_PORT, IASP_NOT_PRESENT }, { IAS_ATTRIBUTE_PROXY_POLICY_NAME, IASP_NONE }, { IAS_ATTRIBUTE_PROVIDER_TYPE, IASP_UNDETERMINED }, { IAS_ATTRIBUTE_REMOTE_SERVER_ADDRESS, IASP_UNDETERMINED }, { IAS_ATTRIBUTE_REASON_CODE, IASP_UNDETERMINED }, { IAS_ATTRIBUTE_REASON_STRING, IASP_UNDETERMINED }, { ATTRIBUTE_UNDEFINED, IASP_UNDETERMINED } }; VOID WINAPI IASRadiusLogResult( IRequest* request, IAttributesRaw* raw ) { // We only care about Access-Requests. LONG type = 0; request->get_Request(&type); if (type != IAS_REQUEST_ACCESS_REQUEST) { return; } // Determine which response type this is. request->get_Response(&type); DWORD eventID; InsertionString* attrs; switch (type) { case IAS_RESPONSE_ACCESS_ACCEPT: eventID = IAS_RESPONSE_ACCEPT; attrs = ACCEPT_ATTRS; break; case IAS_RESPONSE_ACCESS_REJECT: eventID = IAS_RESPONSE_REJECT; attrs = REJECT_ATTRS; break; case IAS_RESPONSE_DISCARD_PACKET: eventID = IAS_RESPONSE_DISCARD; attrs = DISCARD_ATTRS; break; default: return; } // Format the insertion strings. PWSTR strings[24]; DWORD numStrings = 0; for ( ; attrs->attrID != ATTRIBUTE_UNDEFINED; ++attrs, ++numStrings) { strings[numStrings] = formatAttribute( request, raw, attrs->attrID, attrs->defaultValue ); } // Report the event. IASReportEvent( eventID, numStrings, 0, (PCWSTR*)strings, NULL ); // Free the insertion strings. while (numStrings--) { freeString(strings[numStrings]); } }