|
@@ -0,0 +1,213 @@
|
|
|
|
|
+//Set includes
|
|
|
|
|
+#include <iostream>
|
|
|
|
|
+#include <fstream>
|
|
|
|
|
+
|
|
|
|
|
+#include <Windows.h>
|
|
|
|
|
+#include <Authif.h>
|
|
|
|
|
+#include <stdio.h>
|
|
|
|
|
+#include <stdlib.h>
|
|
|
|
|
+#include <ctime>
|
|
|
|
|
+#include <string>
|
|
|
|
|
+#include "WinHttpClient.h"
|
|
|
|
|
+#include <rapidjson\document.h>
|
|
|
|
|
+#include "stdafx.h"
|
|
|
|
|
+
|
|
|
|
|
+//#define _CRT_SECURE_NO_WARNINGS
|
|
|
|
|
+void logger(const char * msg) //Logger function ==> Write to a log file
|
|
|
|
|
+{
|
|
|
|
|
+ FILE * fp = fopen("C:/Temp/NPS.log.txt", "a");
|
|
|
|
|
+ if (fp)
|
|
|
|
|
+ {
|
|
|
|
|
+ fprintf(fp, "%s\n", msg);
|
|
|
|
|
+ fclose(fp);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+DWORD WINAPI RadiusExtensionProcess2(
|
|
|
|
|
+ _Inout_ PRADIUS_EXTENSION_CONTROL_BLOCK pECB //The famous function
|
|
|
|
|
+ )
|
|
|
|
|
+{
|
|
|
|
|
+ if (pECB != NULL) //Check if we got some data from NPS
|
|
|
|
|
+ {
|
|
|
|
|
+ if (pECB->rcRequestType == rcAccessRequest) //Check if the request is a access request
|
|
|
|
|
+ {
|
|
|
|
|
+ RADIUS_ATTRIBUTE_ARRAY * pAR = pECB->GetRequest(pECB); //Get the attribute array
|
|
|
|
|
+ if (pAR != NULL) //Check if the attribute array is not empty
|
|
|
|
|
+ {
|
|
|
|
|
+ //Initialize some variables
|
|
|
|
|
+ char * username = "";
|
|
|
|
|
+ char * password = "";
|
|
|
|
|
+ char * uniqueId = "";
|
|
|
|
|
+ char * clientIp = "";
|
|
|
|
|
+
|
|
|
|
|
+ //Get the size of the attribute array
|
|
|
|
|
+ DWORD size = pAR->GetSize(pAR);
|
|
|
|
|
+
|
|
|
|
|
+ //Pre-init the attribute pointer
|
|
|
|
|
+ const RADIUS_ATTRIBUTE * pRA;
|
|
|
|
|
+
|
|
|
|
|
+ //Loop through each object in attribute array
|
|
|
|
|
+ for (DWORD iAR = 0; iAR < size; iAR++)
|
|
|
|
|
+ {
|
|
|
|
|
+ //Get the attribute from the array
|
|
|
|
|
+ pRA = pAR->AttributeAt(pAR, iAR);
|
|
|
|
|
+ if (pRA != NULL) //Check if the attribute is not empty
|
|
|
|
|
+ {
|
|
|
|
|
+ if(pRA->dwAttrType == ratUserName) //Get the username
|
|
|
|
|
+ {
|
|
|
|
|
+ username = (char *) pRA->lpValue;
|
|
|
|
|
+ }
|
|
|
|
|
+ if(pRA->dwAttrType == ratUniqueId) //Get the request ID
|
|
|
|
|
+ {
|
|
|
|
|
+ uniqueId = (char *) pRA->dwValue;
|
|
|
|
|
+ }
|
|
|
|
|
+ if(pRA->dwAttrType == ratUserPassword) //Get the password (can be empty or "")
|
|
|
|
|
+ {
|
|
|
|
|
+ password = (char *) pRA->lpValue;
|
|
|
|
|
+ }
|
|
|
|
|
+ if(pRA->dwAttrType == ratCallingStationId) //Get the source ip address
|
|
|
|
|
+ {
|
|
|
|
|
+ clientIp = (char *) pRA->dwValue;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //Write the result to the log file
|
|
|
|
|
+ char buft[2048];
|
|
|
|
|
+ sprintf(buft, "Recieved Request (ID:%d) for user: %s, pass: %s",uniqueId, username, password);
|
|
|
|
|
+ logger(buft);
|
|
|
|
|
+
|
|
|
|
|
+ //Init a post request
|
|
|
|
|
+ WinHttpClient post(L"http://192.168.2.240:8080/Implementation/SAS");
|
|
|
|
|
+
|
|
|
|
|
+ //Create the request json string
|
|
|
|
|
+ char dat[2000];
|
|
|
|
|
+ sprintf(dat, "{\"function\":\"authenticate\",\"requestId\":%d,\"username\":\"%s\",\"password\":\"%s\"}", uniqueId, username, password);
|
|
|
|
|
+
|
|
|
|
|
+ //Cast from char to string
|
|
|
|
|
+ string data = string(dat);
|
|
|
|
|
+
|
|
|
|
|
+ //Set request data (send json)
|
|
|
|
|
+ post.SetAdditionalDataToSend((BYTE *)data.c_str(), (int) data.size());
|
|
|
|
|
+
|
|
|
|
|
+ //Set request headers
|
|
|
|
|
+ wchar_t szSize[50] = L"";
|
|
|
|
|
+ swprintf_s(szSize, L"%d", data.size());
|
|
|
|
|
+ wstring headers = L"Content-Length: ";
|
|
|
|
|
+ headers += szSize;
|
|
|
|
|
+ headers += L"\r\nContent-Type: application/x-www-form-urlencoded\r\n";
|
|
|
|
|
+ post.SetAdditionalRequestHeaders(headers);
|
|
|
|
|
+
|
|
|
|
|
+ //Set max timeout
|
|
|
|
|
+ post.SetTimeouts(30000U, 30000U, 30000U, 30000U);
|
|
|
|
|
+
|
|
|
|
|
+ //Execute the post request
|
|
|
|
|
+ if(!post.SendHttpRequest(L"POST", true)) //If it failed log it
|
|
|
|
|
+ {
|
|
|
|
|
+ char answer[2048];
|
|
|
|
|
+ sprintf(answer, "POST FAILED from: %s for id: %d, user: %s", clientIp, uniqueId, username);
|
|
|
|
|
+ logger(answer);
|
|
|
|
|
+ pECB->SetResponseType(pECB, rcAccessReject);
|
|
|
|
|
+ return NO_ERROR;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ //Set the time for our timeout loop
|
|
|
|
|
+ int timeout = 30;
|
|
|
|
|
+
|
|
|
|
|
+ //Pre-init the response var
|
|
|
|
|
+ char * response;
|
|
|
|
|
+
|
|
|
|
|
+ //Our timeout loop
|
|
|
|
|
+ for(int i=1; i<=timeout; i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ //Check if we received some content
|
|
|
|
|
+ if((int) post.GetRawResponseReceivedContentLength() > 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ //YEAHHH!! We received a response
|
|
|
|
|
+ response = (char *) post.GetRawResponseContent();
|
|
|
|
|
+ break; //Exit the loop
|
|
|
|
|
+ }
|
|
|
|
|
+ else if(i >= timeout)
|
|
|
|
|
+ {
|
|
|
|
|
+ //OOPS!! Still no response after our time out time
|
|
|
|
|
+ pECB->SetResponseType(pECB, rcAccessReject); //Set our RADIUS response to reject
|
|
|
|
|
+ return NO_ERROR; //Exit the complete function
|
|
|
|
|
+ }
|
|
|
|
|
+ else //Still no response and within the timeout
|
|
|
|
|
+ {
|
|
|
|
|
+ //Sleep for 1 second (1000 miliseconds)
|
|
|
|
|
+ Sleep(1000);
|
|
|
|
|
+ continue; //Continue the loop
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //Finally out of the loop
|
|
|
|
|
+
|
|
|
|
|
+ //Check again if response is not empty
|
|
|
|
|
+ if(sizeof(response) == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ //If so, exit
|
|
|
|
|
+ pECB->SetResponseType(pECB, rcAccessReject); //Set our RADIUS response to reject
|
|
|
|
|
+ return NO_ERROR; //Exit the complete function
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //Produce a json document from the received content
|
|
|
|
|
+ rapidjson::Document json;
|
|
|
|
|
+ json.Parse(response);
|
|
|
|
|
+
|
|
|
|
|
+ //Pre-init var
|
|
|
|
|
+ int code;
|
|
|
|
|
+
|
|
|
|
|
+ //Check if the received json contains the "result" key
|
|
|
|
|
+ if(json.HasMember("result"))
|
|
|
|
|
+ {
|
|
|
|
|
+ //If so, Get it as an int
|
|
|
|
|
+ if(json["result"].IsInt())
|
|
|
|
|
+ {
|
|
|
|
|
+ //Write it to the code var
|
|
|
|
|
+ code = json["result"].GetInt();
|
|
|
|
|
+ }
|
|
|
|
|
+ else //If it is not an int or it failed deny the request
|
|
|
|
|
+ {
|
|
|
|
|
+ pECB->SetResponseType(pECB, rcAccessReject); //Set our RADIUS response to reject
|
|
|
|
|
+ return NO_ERROR; //Exit the complete function
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else //If the result key doesn't exist, deny the request
|
|
|
|
|
+ {
|
|
|
|
|
+ pECB->SetResponseType(pECB, rcAccessReject); //Set our RADIUS response to reject
|
|
|
|
|
+ return NO_ERROR; //Exit the complete function
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //If the result code is 0 Allow the request
|
|
|
|
|
+ if(code == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ char out[5000];
|
|
|
|
|
+ sprintf(out, "Login SUCCES from %s for id: %d, user: %s", clientIp, uniqueId, username);
|
|
|
|
|
+ logger(out);
|
|
|
|
|
+ pECB->SetResponseType(pECB, rcAccessAccept); //Set our RADIUS response to accept
|
|
|
|
|
+ }
|
|
|
|
|
+ else //Log every other result code
|
|
|
|
|
+ {
|
|
|
|
|
+ char out[5000];
|
|
|
|
|
+ sprintf(out, "Login FAILED from %s for id: %d, user: %s | result==> code: %d, text: %s", clientIp, uniqueId, username, code, json["resultText"].GetString());
|
|
|
|
|
+ logger(out);
|
|
|
|
|
+ pECB->SetResponseType(pECB, rcAccessReject); //Set our RADIUS response to reject
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (pECB->rcRequestType == rcAccountingRequest) //If request type is an accounting request
|
|
|
|
|
+ {
|
|
|
|
|
+ pECB->SetResponseType(pECB, rcAccountingResponse); //Then just answer it
|
|
|
|
|
+ }
|
|
|
|
|
+ else //If we get another request
|
|
|
|
|
+ {
|
|
|
|
|
+ pECB->SetResponseType(pECB, rcUnknown); //We don't know what to do with it
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return NO_ERROR; //Exit the complete function
|
|
|
|
|
+}
|