mirror of
https://github.com/SoftEtherVPN/SoftEtherVPN.git
synced 2024-11-14 05:30:41 +03:00
1990 lines
55 KiB
C
1990 lines
55 KiB
C
// SoftEther VPN Source Code - Developer Edition Master Branch
|
|
// Cedar Communication Module
|
|
//
|
|
// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
|
|
//
|
|
// Copyright (c) Daiyuu Nobori.
|
|
// Copyright (c) SoftEther VPN Project, University of Tsukuba, Japan.
|
|
// Copyright (c) SoftEther Corporation.
|
|
//
|
|
// All Rights Reserved.
|
|
//
|
|
// http://www.softether.org/
|
|
//
|
|
// Author: Tetsuo Sugiyama
|
|
// Comments: Tetsuo Sugiyama, Ph.D.
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU General Public License
|
|
// version 2 as published by the Free Software Foundation.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License version 2
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
|
|
// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
|
|
//
|
|
//
|
|
// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
|
|
// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
|
|
// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
|
|
// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
|
|
// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
|
|
// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
|
|
// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
|
|
// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
|
|
// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
|
|
// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
|
|
// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
|
|
// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
|
|
// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
|
|
// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
|
|
//
|
|
// USE ONLY IN JAPAN. DO NOT USE THIS SOFTWARE IN ANOTHER COUNTRY UNLESS
|
|
// YOU HAVE A CONFIRMATION THAT THIS SOFTWARE DOES NOT VIOLATE ANY
|
|
// CRIMINAL LAWS OR CIVIL RIGHTS IN THAT PARTICULAR COUNTRY. USING THIS
|
|
// SOFTWARE IN OTHER COUNTRIES IS COMPLETELY AT YOUR OWN RISK. THE
|
|
// SOFTETHER VPN PROJECT HAS DEVELOPED AND DISTRIBUTED THIS SOFTWARE TO
|
|
// COMPLY ONLY WITH THE JAPANESE LAWS AND EXISTING CIVIL RIGHTS INCLUDING
|
|
// PATENTS WHICH ARE SUBJECTS APPLY IN JAPAN. OTHER COUNTRIES' LAWS OR
|
|
// CIVIL RIGHTS ARE NONE OF OUR CONCERNS NOR RESPONSIBILITIES. WE HAVE
|
|
// NEVER INVESTIGATED ANY CRIMINAL REGULATIONS, CIVIL LAWS OR
|
|
// INTELLECTUAL PROPERTY RIGHTS INCLUDING PATENTS IN ANY OF OTHER 200+
|
|
// COUNTRIES AND TERRITORIES. BY NATURE, THERE ARE 200+ REGIONS IN THE
|
|
// WORLD, WITH DIFFERENT LAWS. IT IS IMPOSSIBLE TO VERIFY EVERY
|
|
// COUNTRIES' LAWS, REGULATIONS AND CIVIL RIGHTS TO MAKE THE SOFTWARE
|
|
// COMPLY WITH ALL COUNTRIES' LAWS BY THE PROJECT. EVEN IF YOU WILL BE
|
|
// SUED BY A PRIVATE ENTITY OR BE DAMAGED BY A PUBLIC SERVANT IN YOUR
|
|
// COUNTRY, THE DEVELOPERS OF THIS SOFTWARE WILL NEVER BE LIABLE TO
|
|
// RECOVER OR COMPENSATE SUCH DAMAGES, CRIMINAL OR CIVIL
|
|
// RESPONSIBILITIES. NOTE THAT THIS LINE IS NOT LICENSE RESTRICTION BUT
|
|
// JUST A STATEMENT FOR WARNING AND DISCLAIMER.
|
|
//
|
|
//
|
|
// SOURCE CODE CONTRIBUTION
|
|
// ------------------------
|
|
//
|
|
// Your contribution to SoftEther VPN Project is much appreciated.
|
|
// Please send patches to us through GitHub.
|
|
// Read the SoftEther VPN Patch Acceptance Policy in advance:
|
|
// http://www.softether.org/5-download/src/9.patch
|
|
//
|
|
//
|
|
// DEAR SECURITY EXPERTS
|
|
// ---------------------
|
|
//
|
|
// If you find a bug or a security vulnerability please kindly inform us
|
|
// about the problem immediately so that we can fix the security problem
|
|
// to protect a lot of users around the world as soon as possible.
|
|
//
|
|
// Our e-mail address for security reports is:
|
|
// softether-vpn-security [at] softether.org
|
|
//
|
|
// Please note that the above e-mail address is not a technical support
|
|
// inquiry address. If you need technical assistance, please visit
|
|
// http://www.softether.org/ and ask your question on the users forum.
|
|
//
|
|
// Thank you for your cooperation.
|
|
//
|
|
//
|
|
// NO MEMORY OR RESOURCE LEAKS
|
|
// ---------------------------
|
|
//
|
|
// The memory-leaks and resource-leaks verification under the stress
|
|
// test has been passed before release this source code.
|
|
|
|
|
|
// WebUI.c
|
|
// Web User Interface module
|
|
|
|
#include "CedarPch.h"
|
|
|
|
static WU_CONTEXT *WuNewContext(WEBUI *wu, char *hubname);
|
|
static void WuFreeContext(WU_CONTEXT *context);
|
|
static WU_WEBPAGE *WuNewUniWebPage(wchar_t *content);
|
|
static WU_WEBPAGE *WuNewWebPage(char *content, UINT size, char *filename);
|
|
static wchar_t *WuErrorPage(UINT errorcode);
|
|
static wchar_t *WuRedirectPage(char *url);
|
|
static wchar_t *WuUniReadFile(char *filename);
|
|
static void WuUniReplace(wchar_t **buf, wchar_t *from, wchar_t *to);
|
|
static void WuUniInsertBefore(wchar_t **buf, wchar_t *insert, wchar_t *before);
|
|
static LIST *WuAnalyzeTarget(char *target,char *filename, UINT size);
|
|
static void WuFreeStrStrMap(LIST *params);
|
|
static void WuEnableTag(wchar_t **buf, wchar_t *keyword);
|
|
static char *WuNewSessionKey();
|
|
static void WuUniStrReplace(wchar_t **buf, wchar_t *from, char *to);
|
|
static wchar_t *WuUniGetTemplate(wchar_t **str, wchar_t *start, wchar_t *end, bool erase);
|
|
static void WuUniUintReplace(wchar_t **buf, wchar_t *key, UINT num);
|
|
static void WuUniUint64Replace(wchar_t **buf, wchar_t *key, UINT64 num);
|
|
static wchar_t *WuUniGetTemplate(wchar_t **str, wchar_t *start, wchar_t *end, bool erase);
|
|
static LIST *WuUniMakeTable(wchar_t *def);
|
|
static LIST *WuUniMakeTableFromTemplate(wchar_t **str, wchar_t *start, wchar_t *end);
|
|
static void WuExpireSessionKey(WEBUI *wu);
|
|
static WU_CONTEXT *WuGetContext(LIST *contexts, char *sessionkey);
|
|
|
|
#define WP_DEFAULT "/webui/"
|
|
#define WP_LOGIN "/webui/login.cgi"
|
|
#define WP_REDIRECT "/webui/redirect.cgi"
|
|
#define WP_ERROR "/webui/error.cgi"
|
|
#define WP_SERVER "/webui/server.cgi"
|
|
#define WP_LISTENER "/webui/listener.cgi"
|
|
#define WP_HUB "/webui/hub.cgi"
|
|
#define WP_USER "/webui/user.cgi"
|
|
#define WP_EDITUSER "/webui/edituser.cgi"
|
|
#define WP_NEWHUB "/webui/newhub.cgi"
|
|
#define WP_LICENSE "/webui/license.cgi"
|
|
#define WP_LOCALBRIDGE "/webui/localbridge.cgi"
|
|
#define WP_SECURENAT "/webui/securenat.cgi"
|
|
#define WP_SESSION "/webui/session.cgi"
|
|
|
|
static wchar_t *WpDefault(WEBUI *wu, LIST *params);
|
|
static wchar_t *WpLogin(WEBUI *wu, LIST *params);
|
|
static wchar_t *WpServer(WEBUI *wu, LIST *params);
|
|
static wchar_t *WpListener(WEBUI *wu, LIST *params);
|
|
static wchar_t *WpHub(WEBUI *wu, LIST *params);
|
|
static wchar_t *WpUser(WEBUI *wu, LIST *params);
|
|
static wchar_t *WpEditUser(WEBUI *wu, LIST *params);
|
|
static wchar_t *WpNewHub(WEBUI *wu, LIST *params);
|
|
static wchar_t *WpLicense(WEBUI *wu, LIST *params);
|
|
static wchar_t *WpLocalBridge(WEBUI *wu, LIST *params);
|
|
static wchar_t *WpSecureNAT(WEBUI *wu, LIST *params);
|
|
static wchar_t *WpSession(WEBUI *wu, LIST *params);
|
|
|
|
// WebUI page handler table
|
|
static STRMAP_ENTRY wu_pages[] = {
|
|
{WP_DEFAULT, WpDefault},
|
|
{WP_LOGIN, WpLogin},
|
|
{WP_SERVER, WpServer},
|
|
{WP_LISTENER, WpListener},
|
|
{WP_HUB, WpHub},
|
|
{WP_USER, WpUser},
|
|
{WP_EDITUSER, WpEditUser},
|
|
{WP_NEWHUB, WpNewHub},
|
|
{WP_LICENSE, WpLicense},
|
|
{WP_LOCALBRIDGE, WpLocalBridge},
|
|
{WP_SECURENAT, WpSecureNAT},
|
|
{WP_SESSION, WpSession},
|
|
};
|
|
|
|
// **** Page handlers
|
|
|
|
// Redirect the directory access to the login screen
|
|
static wchar_t *WpDefault(WEBUI *wu, LIST *params)
|
|
{
|
|
return WuRedirectPage(WP_LOGIN);
|
|
}
|
|
|
|
// Login page
|
|
static wchar_t *WpLogin(WEBUI *wu, LIST *params)
|
|
{
|
|
UINT result;
|
|
char random[20], securepass[SHA1_SIZE];
|
|
char *password = (char*)StrMapSearch(params, "PASS");
|
|
char *hubname = (char*)StrMapSearch(params, "HUB");
|
|
|
|
if(password == NULL)
|
|
{
|
|
wchar_t *buf = WuUniReadFile("|"WP_LOGIN);
|
|
WuUniStrReplace(&buf, L"ACTION", WP_LOGIN);
|
|
WuUniStrReplace(&buf, L"HUBNAME", hubname == NULL ? "" : hubname);
|
|
return buf;
|
|
}
|
|
|
|
// Administrator authentication
|
|
Rand(random,sizeof(random));
|
|
Hash(securepass, password, StrLen(password), true);
|
|
SecurePassword(securepass, securepass, random);
|
|
result = AdminCheckPassword(wu->Cedar, random, securepass, hubname, false, NULL);
|
|
|
|
if(result == ERR_NO_ERROR)
|
|
{
|
|
// Successful login
|
|
char tmp[MAX_SIZE];
|
|
STRMAP_ENTRY *context;
|
|
|
|
// Create a new context
|
|
context = Malloc(sizeof(STRMAP_ENTRY));
|
|
context->Name = WuNewSessionKey();
|
|
context->Value = WuNewContext(wu, hubname);
|
|
Add(wu->Contexts, context);
|
|
|
|
// Transfer to the server management screen
|
|
Format(tmp, sizeof(tmp), "%s?KEY=%s", WP_SERVER, context->Name);
|
|
return WuRedirectPage(tmp);
|
|
}else{
|
|
// Login failure
|
|
wchar_t *buf = WuUniReadFile("|"WP_LOGIN);
|
|
WuUniStrReplace(&buf, L"ACTION", WP_LOGIN);
|
|
WuUniStrReplace(&buf, L"HUBNAME",hubname == NULL ? "" : hubname);
|
|
WuUniReplace(&buf, L"<!--ERR1-->", GetUniErrorStr(result));
|
|
return buf;
|
|
}
|
|
}
|
|
|
|
// Server management
|
|
static wchar_t *WpServer(WEBUI *wu, LIST *params)
|
|
{
|
|
char *sessionkey = (char*)StrMapSearch(params, "KEY");
|
|
WU_CONTEXT *context = WuGetContext(wu->Contexts, sessionkey);
|
|
UINT i;
|
|
wchar_t *buf;
|
|
LIST *strmap;
|
|
|
|
if(context == NULL)
|
|
{
|
|
return WuRedirectPage(WP_LOGIN);
|
|
}
|
|
|
|
buf = WuUniReadFile("|"WP_SERVER);
|
|
strmap = WuUniMakeTableFromTemplate(&buf, L"<!--STRMAP:", L":STRMAP-->");
|
|
|
|
// Show the Virtual HUB list
|
|
{
|
|
wchar_t *tmpl = WuUniGetTemplate(&buf, L"<!--HUBS_TMPL:", L":HUBS_TMPL-->", true);
|
|
RPC_ENUM_HUB t;
|
|
|
|
t.Hubs = NULL;
|
|
StEnumHub(context->Admin, &t);
|
|
for(i=0; i<t.NumHub; i++)
|
|
{
|
|
wchar_t *tmp = UniCopyStr(tmpl);
|
|
wchar_t lastlogin[MAX_SIZE], lastcomm[MAX_SIZE];
|
|
RPC_ENUM_HUB_ITEM *item = &t.Hubs[i];
|
|
|
|
GetDateTimeStr64Uni(lastlogin,sizeof(lastlogin), SystemToLocal64(item->LastLoginTime));
|
|
GetDateTimeStr64Uni(lastcomm, sizeof(lastcomm), SystemToLocal64(item->LastCommTime));
|
|
WuUniStrReplace(&tmp, L"{HUBNAME}", item->HubName);
|
|
WuUniReplace(&tmp, L"{HUBSTATE}", item->Online ? StrMapSearch(strmap, "HUB_ONLINE") : StrMapSearch(strmap, "HUB_OFFLINE"));
|
|
WuUniReplace(&tmp, L"{HUBTYPE}", item->HubType == HUB_TYPE_STANDALONE ? StrMapSearch(strmap, "HUB_STANDALONE")
|
|
: item->HubType == HUB_TYPE_FARM_DYNAMIC ? StrMapSearch(strmap,"HUB_DYNAMIC") : StrMapSearch(strmap, "HUB_STATIC"));
|
|
WuUniUintReplace(&tmp, L"{HUBUSERS}", item->NumUsers);
|
|
WuUniUintReplace(&tmp, L"{HUBGROUPS}", item->NumGroups);
|
|
WuUniUintReplace(&tmp, L"{HUBSESSIONS}", item->NumSessions);
|
|
WuUniUintReplace(&tmp, L"{HUBMACS}", item->NumMacTables);
|
|
WuUniUintReplace(&tmp, L"{HUBIPS}", item->NumIpTables);
|
|
WuUniUintReplace(&tmp, L"{HUBLOGINS}", item->NumLogin);
|
|
WuUniReplace(&tmp, L"{HUBLASTLOGINDATE}", lastlogin);
|
|
WuUniReplace(&tmp, L"{HUBLASTCOMMDATE}", lastcomm);
|
|
|
|
WuUniInsertBefore(&buf, tmp, L"<!--HUBS-->");
|
|
Free(tmp);
|
|
}
|
|
FreeRpcEnumHub(&t);
|
|
Free(tmpl);
|
|
}
|
|
|
|
// Show the listener list
|
|
{
|
|
RPC_LISTENER_LIST t;
|
|
wchar_t *tmpl = WuUniGetTemplate(&buf, L"<!--LISTENER_TMPL:", L":LISTENER_TMPL-->", true);
|
|
Zero(&t, sizeof(t));
|
|
StEnumListener(context->Admin, &t);
|
|
for(i=0; i<t.NumPort; i++)
|
|
{
|
|
wchar_t *tmp = UniCopyStr(tmpl);
|
|
WuUniReplace(&tmp, L"{PORT_STATE}", t.Enables[i] == false ? StrMapSearch(strmap,"LISTENER_OFFLINE")
|
|
: t.Errors[i] == true ? StrMapSearch(strmap,"LISTENER_ERROR") : StrMapSearch(strmap, "LISTENER_ONLINE"));
|
|
WuUniUintReplace(&tmp, L"{PORTNUM}", t.Ports[i]);
|
|
WuEnableTag(&tmp, t.Enables[i] ? L"STOPA" : L"STARTA");
|
|
WuUniInsertBefore(&buf, tmp, L"<!--LISTENERS-->");
|
|
Free(tmp);
|
|
}
|
|
FreeRpcListenerList(&t);
|
|
Free(tmpl);
|
|
}
|
|
WuUniStrReplace(&buf, L"{LINK_HUB}", WP_HUB);
|
|
WuUniStrReplace(&buf, L"{SESSIONKEY}", sessionkey);
|
|
WuUniStrReplace(&buf, L"{LISTENER_LINK}", WP_LISTENER);
|
|
WuUniStrReplace(&buf, L"{LINK_NEWHUB}", WP_NEWHUB);
|
|
WuUniStrReplace(&buf, L"{LINK_SERVER}", WP_SERVER);
|
|
WuUniStrReplace(&buf, L"{LINK_LICENSE}", WP_LICENSE);
|
|
WuUniStrReplace(&buf, L"{LINK_LOCALBRIDGE}", WP_LOCALBRIDGE);
|
|
|
|
WuFreeStrStrMap(strmap);
|
|
|
|
return buf;
|
|
}
|
|
|
|
// Listener management
|
|
static wchar_t *WpListener(WEBUI *wu, LIST *params)
|
|
{
|
|
char *sessionkey = (char*)StrMapSearch(params, "KEY");
|
|
WU_CONTEXT *context = WuGetContext(wu->Contexts, sessionkey);
|
|
char *cmd = (char*)StrMapSearch(params, "CMD");
|
|
RPC_LISTENER t;
|
|
UINT retcode;
|
|
|
|
if(context == NULL)
|
|
{
|
|
return WuRedirectPage(WP_LOGIN);
|
|
}
|
|
|
|
t.Port = ToInt((char*)StrMapSearch(params, "PORT"));
|
|
|
|
if( StrCmp(cmd, "CREATE") == 0 )
|
|
{
|
|
// Create a new listener
|
|
if(t.Port == 0)
|
|
{
|
|
wchar_t *buf = WuUniReadFile("|"WP_LISTENER);
|
|
WuUniStrReplace(&buf, L"ACTION", WP_LISTENER);
|
|
WuUniStrReplace(&buf, L"SESSIONKEY", sessionkey);
|
|
return buf;
|
|
}
|
|
else
|
|
{
|
|
t.Enable = true;
|
|
retcode = StCreateListener(context->Admin, &t);
|
|
}
|
|
}
|
|
else if( StrCmp(cmd, "DEL")==0 )
|
|
{
|
|
retcode = StDeleteListener(context->Admin, &t);
|
|
}
|
|
else if(StrCmp(cmd, "START")==0 )
|
|
{
|
|
t.Enable = true;
|
|
retcode = StEnableListener(context->Admin, &t);
|
|
}
|
|
else if(StrCmp(cmd, "STOP")==0 )
|
|
{
|
|
t.Enable = false;
|
|
retcode = StEnableListener(context->Admin, &t);
|
|
}
|
|
|
|
if(retcode == ERR_NO_ERROR)
|
|
{
|
|
char tmp[MAX_SIZE];
|
|
Format(tmp, sizeof(tmp), "%s?KEY=%s", WP_SERVER, sessionkey);
|
|
return WuRedirectPage(tmp);
|
|
}
|
|
return WuErrorPage(retcode);
|
|
}
|
|
|
|
// Virtual HUB management
|
|
static wchar_t *WpHub(WEBUI *wu, LIST *params)
|
|
{
|
|
char *hubname = (char*)StrMapSearch(params, "HUB");
|
|
char *sessionkey = (char*)StrMapSearch(params, "KEY");
|
|
char *cmd = (char*)StrMapSearch(params, "CMD");
|
|
WU_CONTEXT *context = WuGetContext(wu->Contexts, sessionkey);
|
|
|
|
// Confirm the session
|
|
if(context == NULL)
|
|
{
|
|
return WuRedirectPage(WP_LOGIN);
|
|
}
|
|
|
|
if(StrCmp(cmd, "ONLINE") == 0 || StrCmp(cmd, "OFFLINE") == 0)
|
|
{
|
|
// Online / offline switching
|
|
UINT retcode;
|
|
RPC_SET_HUB_ONLINE t;
|
|
StrCpy(t.HubName, sizeof(t.HubName), hubname);
|
|
t.Online = (StrCmp(cmd, "ONLINE") == 0) ? true : false;
|
|
retcode = StSetHubOnline(context->Admin, &t);
|
|
if(retcode == ERR_NO_ERROR){
|
|
char tmp[MAX_SIZE];
|
|
Format(tmp, sizeof(tmp), "%s?HUB=%s&KEY=%s", WP_HUB, hubname, sessionkey);
|
|
return WuRedirectPage(tmp);
|
|
}else{
|
|
return WuErrorPage(retcode);
|
|
}
|
|
}
|
|
else if(StrCmp(cmd, "DELETE") == 0)
|
|
{
|
|
// Delete the Virtual HUB
|
|
RPC_DELETE_HUB t;
|
|
UINT retcode;
|
|
StrCpy(t.HubName, sizeof(t.HubName), hubname);
|
|
retcode = StDeleteHub(context->Admin, &t);
|
|
if(retcode == ERR_NO_ERROR)
|
|
{
|
|
char tmp[MAX_SIZE];
|
|
Format(tmp, sizeof(tmp), "%s?KEY=%s", WP_SERVER, sessionkey);
|
|
return WuRedirectPage(tmp);
|
|
}
|
|
return WuErrorPage(retcode);
|
|
}
|
|
else
|
|
{
|
|
// Show the status and commands of the virtual HUB
|
|
RPC_HUB_STATUS t;
|
|
UINT retcode;
|
|
Zero(&t, sizeof(t));
|
|
StrCpy(t.HubName, sizeof(t.HubName), hubname);
|
|
retcode = StGetHubStatus(context->Admin, &t);
|
|
if(retcode == ERR_NO_ERROR)
|
|
{
|
|
wchar_t tmp[MAX_SIZE];
|
|
wchar_t *buf = WuUniReadFile("|"WP_HUB);
|
|
LIST *strmap = WuUniMakeTableFromTemplate(&buf, L"<!--STRMAP:", L":STRMAP-->");
|
|
|
|
WuUniStrReplace(&buf, L"{HUBNAME}", t.HubName);
|
|
WuUniReplace(&buf, L"{HUBSTATE}", StrMapSearch(strmap, t.Online == false ? "HUB_OFFLINE" : "HUB_ONLINE"));
|
|
WuUniReplace(&buf, L"{HUBTYPE}", GetHubTypeStr(t.HubType));
|
|
WuUniReplace(&buf, L"{HUBSNAT}", StrMapSearch(strmap, t.SecureNATEnabled == false ? "SECNAT_OFF" : "SECNAT_ON"));
|
|
WuUniUintReplace(&buf, L"{HUBSESSIONS}", t.NumSessions);
|
|
WuUniUintReplace(&buf, L"{HUBACLS}", t.NumAccessLists);
|
|
WuUniUintReplace(&buf, L"{HUBUSERS}", t.NumUsers);
|
|
WuUniUintReplace(&buf, L"{HUBGROUPS}", t.NumGroups);
|
|
WuUniUintReplace(&buf, L"{HUBMACTBLS}", t.NumMacTables);
|
|
WuUniUintReplace(&buf, L"{HUBIPTBLS}", t.NumIpTables);
|
|
WuUniUintReplace(&buf, L"{HUBLOGINS}", t.NumLogin);
|
|
GetDateTimeStr64Uni(tmp, sizeof(tmp), SystemToLocal64(t.LastLoginTime));
|
|
WuUniReplace(&buf, L"{HUBLASTLOGIN}", tmp);
|
|
GetDateTimeStr64Uni(tmp, sizeof(tmp), SystemToLocal64(t.LastCommTime));
|
|
WuUniReplace(&buf, L"{HUBLASTCOMM}", tmp);
|
|
WuUniUint64Replace(&buf, L"{HUBTXUNIPKTS}", t.Traffic.Send.UnicastCount);
|
|
WuUniUint64Replace(&buf, L"{HUBTXUNISIZE}", t.Traffic.Send.UnicastBytes);
|
|
WuUniUint64Replace(&buf, L"{HUBTXBRPKTS}", t.Traffic.Send.BroadcastCount);
|
|
WuUniUint64Replace(&buf, L"{HUBTXBRSIZE}", t.Traffic.Send.BroadcastBytes);
|
|
WuUniUint64Replace(&buf, L"{HUBRXUNIPKTS}", t.Traffic.Recv.UnicastCount);
|
|
WuUniUint64Replace(&buf, L"{HUBRXUNISIZE}", t.Traffic.Recv.UnicastBytes);
|
|
WuUniUint64Replace(&buf, L"{HUBRXBRPKTS}", t.Traffic.Recv.BroadcastCount);
|
|
WuUniUint64Replace(&buf, L"{HUBRXBRSIZE}", t.Traffic.Recv.BroadcastBytes);
|
|
|
|
WuEnableTag(&buf, t.Online ? L"ENABLE_OFFLINE" : L"ENABLE_ONLINE");
|
|
|
|
WuUniStrReplace(&buf, L"{LINK_HUB}", WP_HUB);
|
|
WuUniStrReplace(&buf, L"{LINK_USER}", WP_USER);
|
|
WuUniStrReplace(&buf, L"{LINK_SERVER}", WP_SERVER);
|
|
WuUniStrReplace(&buf, L"{LINK_SESSION}", WP_SESSION);
|
|
WuUniStrReplace(&buf, L"{HUBNAME}", hubname);
|
|
WuUniStrReplace(&buf, L"{SESSIONKEY}", sessionkey);
|
|
WuUniStrReplace(&buf, L"{LINK_SECURENAT}", WP_SECURENAT);
|
|
|
|
WuFreeStrStrMap(strmap);
|
|
|
|
return buf;
|
|
}else{
|
|
return WuErrorPage(retcode);
|
|
}
|
|
}
|
|
}
|
|
|
|
// User list
|
|
static wchar_t *WpUser(WEBUI *wu, LIST *params)
|
|
{
|
|
char *sessionkey = (char*)StrMapSearch(params, "KEY");
|
|
WU_CONTEXT *context = WuGetContext(wu->Contexts, sessionkey);
|
|
char *hubname = (char*)StrMapSearch(params, "HUB");
|
|
char *cmd = (char*)StrMapSearch(params, "CMD");
|
|
UINT retcode;
|
|
RPC_ENUM_USER t;
|
|
|
|
// Check the context
|
|
if(context == NULL)
|
|
{
|
|
return WuRedirectPage(WP_LOGIN);
|
|
}
|
|
|
|
if(cmd != NULL && StrCmp(cmd, "DEL") == 0)
|
|
{
|
|
char *username = (char*)StrMapSearch(params, "USER");
|
|
RPC_DELETE_USER t;
|
|
UINT retcode;
|
|
|
|
StrCpy(t.HubName, sizeof(t.HubName), hubname);
|
|
StrCpy(t.Name, sizeof(t.Name), username);
|
|
retcode = StDeleteUser(context->Admin, &t);
|
|
if(retcode == ERR_NO_ERROR)
|
|
{
|
|
char tmp[MAX_SIZE];
|
|
Format(tmp, sizeof(tmp), "%s?HUB=%s&KEY=%s", WP_USER, hubname, sessionkey);
|
|
return WuRedirectPage(tmp);
|
|
}else
|
|
{
|
|
return WuErrorPage(retcode);
|
|
}
|
|
}
|
|
|
|
Zero(&t, sizeof(t));
|
|
StrCpy(t.HubName, sizeof(t.HubName), hubname);
|
|
retcode = StEnumUser(context->Admin, &t);
|
|
if(retcode == ERR_NO_ERROR)
|
|
{
|
|
UINT i;
|
|
wchar_t *buf = WuUniReadFile("|"WP_USER);
|
|
wchar_t *tmpl = WuUniGetTemplate(&buf, L"<!--USER_TMPL:", L"-->", true);
|
|
wchar_t tmp[MAX_SIZE];
|
|
wchar_t datestr[MAX_SIZE];
|
|
|
|
for(i=0; i<t.NumUser; i++)
|
|
{
|
|
RPC_ENUM_USER_ITEM *item = &t.Users[i];
|
|
GetDateTimeStr64Uni(datestr, sizeof(datestr), SystemToLocal64(item->LastLoginTime));
|
|
UniFormat(tmp, sizeof(tmp), tmpl, item->Name, item->Name, item->Name, item->Realname, item->GroupName,
|
|
item->Note, GetAuthTypeStr(item->AuthType), item->NumLogin, datestr);
|
|
WuUniInsertBefore(&buf, tmp, L"<!--USERS-->");
|
|
}
|
|
WuUniStrReplace(&buf, L"{SESSIONKEY}", sessionkey);
|
|
WuUniStrReplace(&buf, L"{HUBNAME}", hubname);
|
|
WuUniStrReplace(&buf, L"{LINK_USER}", WP_USER);
|
|
WuUniStrReplace(&buf, L"{LINK_EDITUSER}", WP_EDITUSER);
|
|
WuUniStrReplace(&buf, L"{LINK_HUB}", WP_HUB);
|
|
|
|
FreeRpcEnumUser(&t);
|
|
Free(tmpl);
|
|
return buf;
|
|
}else{
|
|
return WuErrorPage(retcode);
|
|
}
|
|
}
|
|
|
|
// User edit page
|
|
static wchar_t *WpEditUser(WEBUI *wu, LIST *params)
|
|
{
|
|
char *sessionkey = (char*)StrMapSearch(params, "KEY");
|
|
WU_CONTEXT *context = WuGetContext(wu->Contexts, sessionkey);
|
|
char *hubname = (char*)StrMapSearch(params, "HUB");
|
|
char *username = (char*)StrMapSearch(params, "USER");
|
|
char *cmd = (char*)StrMapSearch(params, "CMD");
|
|
char tmp[MAX_SIZE];
|
|
wchar_t utmp[MAX_SIZE];
|
|
UINT retcode;
|
|
RPC_SET_USER t;
|
|
wchar_t *buf;
|
|
|
|
// Check the context
|
|
if(context == NULL)
|
|
{
|
|
return WuRedirectPage(WP_LOGIN);
|
|
}
|
|
|
|
if(cmd != NULL && (StrCmp(cmd, "SET") == 0 || StrCmp(cmd, "CREATE") == 0))
|
|
{
|
|
char *authtype = (char*)StrMapSearch(params, "AUTHTYPE");
|
|
char *password = (char*)StrMapSearch(params, "PASSWORD");
|
|
char *password2 = (char*)StrMapSearch(params, "PASSWORD2");
|
|
bool create = (StrCmp(cmd, "CREATE") == 0);
|
|
|
|
Zero(&t, sizeof(t));
|
|
StrCpy(t.Name, sizeof(t.Name), username);
|
|
StrCpy(t.HubName, sizeof(t.HubName), hubname);
|
|
|
|
// Read the original user data in the case of edit mode.
|
|
if(!create)
|
|
{
|
|
retcode = StGetUser(context->Admin, &t);
|
|
if(retcode != ERR_NO_ERROR)
|
|
{
|
|
return WuErrorPage(retcode);
|
|
}
|
|
}
|
|
|
|
// Set the authentication method
|
|
if(StrCmp(authtype, "ANONYMOUS") == 0)
|
|
{
|
|
FreeAuthData(t.AuthType, t.AuthData);
|
|
t.AuthType = AUTHTYPE_ANONYMOUS;
|
|
t.AuthData = NULL;
|
|
}
|
|
else if(StrCmp(authtype, "PASSWORD") == 0)
|
|
{
|
|
if(StrCmp(password,password2) != 0)
|
|
{
|
|
// Password for confirmation is mismatched
|
|
return WuErrorPage(ERR_INVALID_PARAMETER);
|
|
}
|
|
|
|
// If the password field has not changed, leave as is
|
|
if(t.AuthType != AUTHTYPE_PASSWORD || StrCmp(password, WU_PASSWORD_NOCHANGE) != 0)
|
|
{
|
|
FreeAuthData(t.AuthType, t.AuthData);
|
|
t.AuthType = AUTHTYPE_PASSWORD;
|
|
t.AuthData = NewPasswordAuthData(username, password);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Parameters of the authentication method is invalid
|
|
return WuErrorPage(ERR_INVALID_PARAMETER);
|
|
}
|
|
|
|
// Set the user information
|
|
if(create)
|
|
{
|
|
retcode = StCreateUser(context->Admin, &t);
|
|
}
|
|
else
|
|
{
|
|
retcode = StSetUser(context->Admin, &t);
|
|
}
|
|
if(retcode != ERR_NO_ERROR)
|
|
{
|
|
return WuErrorPage(retcode);
|
|
}
|
|
|
|
Format(tmp, sizeof(tmp), "%s?KEY=%s&HUB=%s", WP_USER, sessionkey, hubname);
|
|
return WuRedirectPage(tmp);
|
|
}
|
|
|
|
// Generate the user edit page
|
|
Zero(&t, sizeof(t));
|
|
StrCpy(t.HubName, sizeof(t.HubName), hubname);
|
|
|
|
if( username == NULL )
|
|
{
|
|
t.AuthType = AUTHTYPE_PASSWORD;
|
|
}else{
|
|
UINT retcode;
|
|
StrCpy(t.Name, sizeof(t.Name), username);
|
|
retcode = StGetUser(context->Admin, &t);
|
|
if(retcode != ERR_NO_ERROR)
|
|
{
|
|
return WuErrorPage(retcode);
|
|
}
|
|
}
|
|
|
|
buf = WuUniReadFile("|"WP_EDITUSER);
|
|
|
|
if( username == NULL)
|
|
{
|
|
WuEnableTag(&buf, L"{USERNAMEINPUT}");
|
|
WuUniReplace(&buf, L"{USERNAME}", L"");
|
|
WuUniReplace(&buf, L"{CMDNAME}", L"CREATE");
|
|
WuUniReplace(&buf, L"{PASSWORD}", L"");
|
|
}
|
|
else
|
|
{
|
|
WuEnableTag(&buf, L"{USERNAMEHIDDEN}");
|
|
WuUniStrReplace(&buf, L"{USERNAME}", username);
|
|
WuUniReplace(&buf, L"{CMDNAME}", L"SET");
|
|
WuUniStrReplace(&buf, L"{PASSWORD}", WU_PASSWORD_NOCHANGE);
|
|
}
|
|
|
|
// Select the authentication method
|
|
if(t.AuthType == AUTHTYPE_ANONYMOUS)
|
|
{
|
|
WuUniReplace(&buf, L"{SELANONYM}", L"checked");
|
|
}
|
|
else
|
|
{
|
|
WuUniReplace(&buf, L"{SELANONYM}", L"");
|
|
if(t.AuthType == AUTHTYPE_PASSWORD)
|
|
{
|
|
WuUniReplace(&buf, L"{SELPASSWD}", L"checked");
|
|
}
|
|
else
|
|
{
|
|
WuUniReplace(&buf, L"{SELPASSWD}", L"");
|
|
}
|
|
}
|
|
|
|
WuUniReplace(&buf, L"{REALNAME}", t.Realname);
|
|
WuUniReplace(&buf, L"{NOTETEXT}", t.Note);
|
|
WuUniStrReplace(&buf, L"{GROUPNAME}", t.GroupName);
|
|
GetDateTimeStr64Uni(utmp, sizeof(utmp), SystemToLocal64(t.ExpireTime));
|
|
WuUniReplace(&buf, L"{EXPIREDATE}", utmp);
|
|
|
|
WuUniStrReplace(&buf, L"{SESSIONKEY}", sessionkey);
|
|
WuUniStrReplace(&buf, L"{HUBNAME}", hubname);
|
|
WuUniStrReplace(&buf, L"{LINK_EDITUSER}", WP_EDITUSER);
|
|
WuUniStrReplace(&buf, L"{LINK_USER}", WP_USER);
|
|
|
|
return buf;
|
|
}
|
|
|
|
// Create a new Virtual HUB
|
|
static wchar_t *WpNewHub(WEBUI *wu, LIST *params)
|
|
{
|
|
char *sessionkey = (char*)StrMapSearch(params, "KEY");
|
|
WU_CONTEXT *context = WuGetContext(wu->Contexts, sessionkey);
|
|
char *cmd = (char*)StrMapSearch(params, "CMD");
|
|
wchar_t *buf;
|
|
|
|
if(context == NULL)
|
|
{
|
|
return WuRedirectPage(WP_LOGIN);
|
|
}
|
|
|
|
if(StrCmp(cmd, "CREATE") == 0)
|
|
{
|
|
UINT retcode;
|
|
char tmp[MAX_SIZE];
|
|
RPC_CREATE_HUB t;
|
|
RPC_SERVER_INFO t2;
|
|
char *hubname = (char*)StrMapSearch(params, "NAME");
|
|
char *passwd = (char*)StrMapSearch(params, "PASSWD");
|
|
char *passwd2 = (char*)StrMapSearch(params, "PASSWD2");
|
|
|
|
if(strcmp(passwd,passwd2) != 0)
|
|
{
|
|
return WuErrorPage(ERR_INVALID_PARAMETER);
|
|
}
|
|
|
|
Zero(&t, sizeof(t));
|
|
StrCpy(t.HubName, sizeof(t.HubName), hubname);
|
|
Hash(t.HashedPassword, passwd, StrLen(passwd), true);
|
|
HashPassword(t.SecurePassword, ADMINISTRATOR_USERNAME, passwd);
|
|
t.Online = true;
|
|
t.HubType = HUB_TYPE_STANDALONE;
|
|
|
|
// Set to dynamic HUB in the case of cluster controller
|
|
Zero(&t2, sizeof(t2));
|
|
if (StGetServerInfo(context->Admin, &t2) == ERR_NO_ERROR)
|
|
{
|
|
if (t2.ServerType == SERVER_TYPE_FARM_CONTROLLER)
|
|
{
|
|
t.HubType = HUB_TYPE_FARM_DYNAMIC;
|
|
}
|
|
FreeRpcServerInfo(&t2);
|
|
}
|
|
|
|
retcode = StCreateHub(context->Admin, &t);
|
|
if(retcode != ERR_NO_ERROR)
|
|
{
|
|
return WuErrorPage(retcode);
|
|
}
|
|
|
|
Format(tmp, sizeof(tmp), "%s?KEY=%s", WP_SERVER, sessionkey);
|
|
return WuRedirectPage(tmp);
|
|
}
|
|
|
|
buf = WuUniReadFile("|"WP_NEWHUB);
|
|
WuUniStrReplace(&buf, L"{SESSIONKEY}", sessionkey);
|
|
WuUniStrReplace(&buf, L"{LINK_NEWHUB}", WP_NEWHUB);
|
|
WuUniStrReplace(&buf, L"{LINK_SERVER}", WP_SERVER);
|
|
return buf;
|
|
}
|
|
|
|
// License management page
|
|
static wchar_t *WpLicense(WEBUI *wu, LIST *params)
|
|
{
|
|
char *sessionkey = (char*)StrMapSearch(params, "KEY");
|
|
WU_CONTEXT *context = WuGetContext(wu->Contexts, sessionkey);
|
|
char *cmd = (char*)StrMapSearch(params, "CMD");
|
|
UINT retcode;
|
|
wchar_t *buf;
|
|
LIST *strmap;
|
|
|
|
if(context == NULL)
|
|
{
|
|
return WuRedirectPage(WP_LOGIN);
|
|
}
|
|
|
|
// Add a license
|
|
if(StrCmp(cmd, "ADD") == 0)
|
|
{
|
|
RPC_TEST t;
|
|
char tmp[MAX_SIZE];
|
|
char *licensekey = (char*)StrMapSearch(params, "KEYSTRINGS");
|
|
|
|
|
|
Zero(&t, sizeof(t));
|
|
StrCpy(t.StrValue, sizeof(t.StrValue), licensekey);
|
|
|
|
retcode = StAddLicenseKey(context->Admin, &t);
|
|
if(retcode != ERR_NO_ERROR)
|
|
{
|
|
return WuErrorPage(retcode);
|
|
}
|
|
|
|
Format(tmp, sizeof(tmp), "%s?KEY=%s", WP_LICENSE, sessionkey);
|
|
return WuRedirectPage(tmp);
|
|
|
|
}
|
|
// Remove the license
|
|
else if(StrCmp(cmd, "DEL") == 0)
|
|
{
|
|
RPC_TEST t;
|
|
char tmp[MAX_SIZE];
|
|
char *id = (char*)StrMapSearch(params, "ID");
|
|
|
|
Zero(&t, sizeof(t));
|
|
t.IntValue = ToInt(id);
|
|
|
|
retcode = StDelLicenseKey(context->Admin, &t);
|
|
if(retcode != ERR_NO_ERROR)
|
|
{
|
|
return WuErrorPage(retcode);
|
|
}
|
|
|
|
Format(tmp, sizeof(tmp), "%s?KEY=%s", WP_LICENSE, sessionkey);
|
|
return WuRedirectPage(tmp);
|
|
}
|
|
|
|
buf = WuUniReadFile("|"WP_LICENSE);
|
|
strmap = WuUniMakeTableFromTemplate(&buf, L"<!--STRMAP:", L"-->");
|
|
|
|
// Enumerate the license keys
|
|
{
|
|
UINT i;
|
|
RPC_ENUM_LICENSE_KEY t;
|
|
wchar_t *tmpl;
|
|
Zero(&t, sizeof(t));
|
|
|
|
retcode = StEnumLicenseKey(context->Admin, &t);
|
|
|
|
if(retcode != ERR_NO_ERROR)
|
|
{
|
|
WuFreeStrStrMap(strmap);
|
|
Free(buf);
|
|
return WuErrorPage(retcode);
|
|
}
|
|
|
|
tmpl = WuUniGetTemplate(&buf, L"<!--LICENSES_TMPL:", L":LICENSES_TMPL-->", true);
|
|
|
|
for(i = 0; i < t.NumItem; i++)
|
|
{
|
|
wchar_t *status, expires[128];
|
|
wchar_t *tmp = UniCopyStr(tmpl);
|
|
RPC_ENUM_LICENSE_KEY_ITEM *item = &t.Items[i];
|
|
|
|
status = LiGetLicenseStatusStr(item->Status);
|
|
|
|
if(item->Expires == 0)
|
|
{
|
|
UniStrCpy(expires, sizeof(expires), StrMapSearch(strmap, "EXPIRE_INFINITE"));
|
|
}
|
|
else
|
|
{
|
|
GetDateStrEx64(expires, sizeof(expires), item->Expires, NULL);
|
|
}
|
|
|
|
WuUniUintReplace(&tmp, L"{ID}", i);
|
|
WuUniStrReplace(&tmp, L"{LICENSEKEY}", item->LicenseKey);
|
|
WuUniStrReplace(&tmp, L"{LICENSENAME}", item->LicenseName);
|
|
WuUniReplace(&tmp, L"{STATUS}", status);
|
|
WuUniReplace(&tmp, L"{EXPIRES}", expires);
|
|
WuUniStrReplace(&tmp, L"{LICENSEID}", item->LicenseId);
|
|
WuUniUintReplace(&tmp, L"{PRODUCTID}", item->ProductId);
|
|
WuUniUint64Replace(&tmp, L"{SYSTEMID}", item->SystemId);
|
|
WuUniUintReplace(&tmp, L"{SERIALID}", item->SerialId);
|
|
|
|
WuUniInsertBefore(&buf, tmp, L"<!--LICENSES-->");
|
|
Free(tmp);
|
|
}
|
|
FreeRpcEnumLicenseKey(&t);
|
|
Free(tmpl);
|
|
}
|
|
|
|
// Show the license status
|
|
{
|
|
RPC_LICENSE_STATUS t;
|
|
|
|
Zero(&t, sizeof(t));
|
|
|
|
retcode = StGetLicenseStatus(context->Admin, &t);
|
|
|
|
if(retcode != ERR_NO_ERROR)
|
|
{
|
|
WuFreeStrStrMap(strmap);
|
|
Free(buf);
|
|
return WuErrorPage(retcode);
|
|
}
|
|
|
|
WuUniStrReplace(&buf, L"{LSEDITIONNAME}", t.EditionStr);
|
|
WuUniUint64Replace(&buf, L"{LSSERVERID}", t.SystemId);
|
|
if(t.SystemExpires == 0)
|
|
{
|
|
WuUniReplace(&buf, L"{LSEXPIRES}", StrMapSearch(strmap, "NOEXPIRE"));
|
|
}
|
|
else
|
|
{
|
|
wchar_t expires[128];
|
|
GetDateStrEx64(expires, sizeof(expires), t.SystemExpires, NULL);
|
|
WuUniReplace(&buf, L"{LSEXPIRES}", expires);
|
|
}
|
|
|
|
if(t.NumBridgeConnectLicense == INFINITE)
|
|
{
|
|
WuUniReplace(&buf, L"{LSNUMBRIDGES}", StrMapSearch(strmap, "LICENSE_INFINITE"));
|
|
}
|
|
else
|
|
{
|
|
WuUniUintReplace(&buf, L"{LSNUMBRIDGES}", t.NumBridgeConnectLicense);
|
|
}
|
|
|
|
if(t.NumClientConnectLicense == INFINITE)
|
|
{
|
|
WuUniReplace(&buf, L"{LSNUMCLIENTS}", StrMapSearch(strmap, "LICENSE_INFINITE"));
|
|
}
|
|
else
|
|
{
|
|
WuUniUintReplace(&buf, L"{LSNUMCLIENTS}", t.NumClientConnectLicense);
|
|
}
|
|
|
|
}
|
|
|
|
WuUniStrReplace(&buf, L"{LINK_LICENSE}", WP_LICENSE);
|
|
WuUniStrReplace(&buf, L"{LINK_SERVER}", WP_SERVER);
|
|
WuUniStrReplace(&buf, L"{SESSIONKEY}", sessionkey);
|
|
WuFreeStrStrMap(strmap);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
// Local bridge setup page
|
|
static wchar_t *WpLocalBridge(WEBUI *wu, LIST *params)
|
|
{
|
|
char *sessionkey = (char*)StrMapSearch(params, "KEY");
|
|
WU_CONTEXT *context = WuGetContext(wu->Contexts, sessionkey);
|
|
char *cmd = (char*)StrMapSearch(params, "CMD");
|
|
UINT retcode;
|
|
wchar_t *buf;
|
|
LIST *strmap;
|
|
|
|
if(context == NULL)
|
|
{
|
|
return WuRedirectPage(WP_LOGIN);
|
|
}
|
|
|
|
// Create a local bridge
|
|
if(StrCmp(cmd, "CREATE") == 0)
|
|
{
|
|
RPC_LOCALBRIDGE t;
|
|
RPC_ENUM_ETH eth;
|
|
char tmp[MAX_SIZE];
|
|
char *tapmode = (char*)StrMapSearch(params, "TAPMODE");
|
|
char *tapname = (char*)StrMapSearch(params, "TAPNAME");
|
|
char *devid = (char*)StrMapSearch(params, "DEVID");
|
|
char *hubname = (char*)StrMapSearch(params, "LBHUBNAME");
|
|
UINT id = ToInt(devid);
|
|
|
|
Zero(ð, sizeof(eth));
|
|
retcode = StEnumEthernet(context->Admin, ð);
|
|
|
|
if(retcode != ERR_NO_ERROR)
|
|
{
|
|
FreeRpcEnumEth(ð);
|
|
return WuErrorPage(retcode);
|
|
}
|
|
|
|
Zero(&t, sizeof(t));
|
|
t.Active = true;
|
|
if(StrCmp(tapmode, "YES") == 0)
|
|
{
|
|
t.TapMode = true;
|
|
StrCpy(t.DeviceName, sizeof(t.DeviceName), tapname);
|
|
}
|
|
else
|
|
{
|
|
t.TapMode = false;
|
|
StrCpy(t.DeviceName, sizeof(t.DeviceName), eth.Items[id].DeviceName);
|
|
}
|
|
StrCpy(t.HubName, sizeof(t.HubName), hubname);
|
|
t.Online = true;
|
|
FreeRpcEnumEth(ð);
|
|
|
|
retcode = StAddLocalBridge(context->Admin, &t);
|
|
|
|
if(retcode != ERR_NO_ERROR)
|
|
{
|
|
return WuErrorPage(retcode);
|
|
}
|
|
|
|
Format(tmp, sizeof(tmp), "%s?KEY=%s", WP_LOCALBRIDGE, sessionkey);
|
|
return WuRedirectPage(tmp);
|
|
}
|
|
|
|
// Delete the local bridge
|
|
if(StrCmp(cmd, "DEL") == 0)
|
|
{
|
|
RPC_LOCALBRIDGE t;
|
|
RPC_ENUM_LOCALBRIDGE et;
|
|
char tmp[MAX_SIZE];
|
|
char *listid = (char*)StrMapSearch(params, "LISTID");
|
|
UINT id = ToInt(listid);
|
|
|
|
Zero(&et, sizeof(et));
|
|
retcode = StEnumLocalBridge(context->Admin, &et);
|
|
if(retcode != ERR_NO_ERROR)
|
|
{
|
|
return WuErrorPage(retcode);
|
|
}
|
|
|
|
Zero(&t, sizeof(t));
|
|
StrCpy(t.DeviceName, sizeof(t.DeviceName), et.Items[id].DeviceName);
|
|
StrCpy(t.HubName, sizeof(t.HubName), et.Items[id].HubName);
|
|
FreeRpcEnumLocalBridge(&et);
|
|
|
|
retcode = StDeleteLocalBridge(context->Admin, &t);
|
|
|
|
if(retcode != ERR_NO_ERROR)
|
|
{
|
|
return WuErrorPage(retcode);
|
|
}
|
|
|
|
Format(tmp, sizeof(tmp), "%s?KEY=%s", WP_LOCALBRIDGE, sessionkey);
|
|
return WuRedirectPage(tmp);
|
|
}
|
|
|
|
// Show the current local bridge list and the Virtual HUB list and the device list to be bridged
|
|
buf = WuUniReadFile("|"WP_LOCALBRIDGE);
|
|
strmap = WuUniMakeTableFromTemplate(&buf, L"<!--STRMAP:", L"-->");
|
|
|
|
// Show the current local bridge list
|
|
{
|
|
UINT i;
|
|
RPC_ENUM_LOCALBRIDGE t;
|
|
wchar_t *tmpl;
|
|
|
|
Zero(&t, sizeof(t));
|
|
retcode = StEnumLocalBridge(context->Admin, &t);
|
|
|
|
if(retcode != ERR_NO_ERROR)
|
|
{
|
|
FreeRpcEnumLocalBridge(&t);
|
|
Free(buf);
|
|
WuFreeStrStrMap(strmap);
|
|
return WuErrorPage(retcode);
|
|
}
|
|
|
|
tmpl = WuUniGetTemplate(&buf, L"<!--LBLIST_TMPL", L"LBLIST_TMPL-->", true);
|
|
|
|
for(i = 0; i < t.NumItem; i++)
|
|
{
|
|
RPC_LOCALBRIDGE *item = &t.Items[i];
|
|
wchar_t *tmp = UniCopyStr(tmpl);
|
|
WuUniUintReplace(&tmp, L"{LISTID}", i);
|
|
WuUniStrReplace(&tmp, L"{HUBNAME}", item->HubName);
|
|
WuUniStrReplace(&tmp, L"{DEVICENAME}", item->DeviceName);
|
|
WuUniReplace(&tmp, L"{STATUS}", item->Online ? item->Active ? StrMapSearch(strmap, "BRIDGE_ONLINE")
|
|
: StrMapSearch(strmap, "BRIDGE_ERROR") : StrMapSearch(strmap, "BRIDGE_OFFLINE"));
|
|
WuUniInsertBefore(&buf, tmp, L"<!--LBLIST-->");
|
|
Free(tmp);
|
|
}
|
|
Free(tmpl);
|
|
FreeRpcEnumLocalBridge(&t);
|
|
}
|
|
|
|
// Show the Virtual HUB list
|
|
{
|
|
wchar_t *tmpl;
|
|
RPC_ENUM_HUB t;
|
|
UINT i;
|
|
|
|
Zero(&t, sizeof(t));
|
|
retcode = StEnumHub(context->Admin, &t);
|
|
|
|
if(retcode != ERR_NO_ERROR)
|
|
{
|
|
FreeRpcEnumHub(&t);
|
|
Free(buf);
|
|
WuFreeStrStrMap(strmap);
|
|
return WuErrorPage(retcode);
|
|
}
|
|
|
|
tmpl = WuUniGetTemplate(&buf, L"<!--HUBS_TMPL", L"HUBS_TMPL-->", true);
|
|
for(i=0; i<t.NumHub; i++)
|
|
{
|
|
wchar_t *tmp = UniCopyStr(tmpl);
|
|
WuUniStrReplace(&tmp, L"{LBHUBNAME}", t.Hubs[i].HubName);
|
|
WuUniInsertBefore(&buf, tmp, L"<!--HUBS-->");
|
|
Free(tmp);
|
|
}
|
|
FreeRpcEnumHub(&t);
|
|
Free(tmpl);
|
|
}
|
|
|
|
// Get the device list to be bridge
|
|
{
|
|
UINT i;
|
|
RPC_ENUM_ETH t;
|
|
wchar_t *tmpl;
|
|
|
|
Zero(&t, sizeof(t));
|
|
retcode = StEnumEthernet(context->Admin, &t);
|
|
|
|
if(retcode != ERR_NO_ERROR)
|
|
{
|
|
FreeRpcEnumEth(&t);
|
|
Free(buf);
|
|
WuFreeStrStrMap(strmap);
|
|
return WuErrorPage(retcode);
|
|
}
|
|
|
|
tmpl = WuUniGetTemplate(&buf, L"<!--LBDEVLIST_TMPL", L"LBDEVLIST_TMPL-->", true);
|
|
|
|
for(i = 0; i < t.NumItem; i++)
|
|
{
|
|
wchar_t *tmp = UniCopyStr(tmpl);
|
|
WuUniUintReplace(&tmp, L"{DEVID}", i);
|
|
WuUniStrReplace(&tmp, L"{ABLEDEVICE}", t.Items[i].DeviceName);
|
|
WuUniInsertBefore(&buf, tmp, L"<!--LBDEVLIST-->");
|
|
Free(tmp);
|
|
}
|
|
FreeRpcEnumEth(&t);
|
|
Free(tmpl);
|
|
}
|
|
|
|
WuUniStrReplace(&buf, L"{LINK_LOCALBRIDGE}", WP_LOCALBRIDGE);
|
|
WuUniStrReplace(&buf, L"{LINK_SERVER}", WP_SERVER);
|
|
WuUniStrReplace(&buf, L"{SESSIONKEY}", sessionkey);
|
|
WuFreeStrStrMap(strmap);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
// Configure the virtual DHCP function and virtual NAT (SecureNAT)
|
|
static wchar_t *WpSecureNAT(WEBUI *wu, LIST *params)
|
|
{
|
|
char *sessionkey = (char*)StrMapSearch(params, "KEY");
|
|
|
|
WU_CONTEXT *context = WuGetContext(wu->Contexts, sessionkey);
|
|
char *cmd = (char*)StrMapSearch(params, "CMD");
|
|
char *hubname = (char*)StrMapSearch(params, "HUB");
|
|
|
|
UINT retcode;
|
|
wchar_t *buf;
|
|
|
|
if(context == NULL)
|
|
{
|
|
return WuRedirectPage(WP_LOGIN);
|
|
}
|
|
|
|
// Enable / disable the SecureNAT function
|
|
if(StrCmp(cmd, "ENABLE") == 0 || StrCmp(cmd, "DISABLE") == 0)
|
|
{
|
|
RPC_HUB t;
|
|
char tmp[MAX_SIZE];
|
|
|
|
Zero(&t, sizeof(t));
|
|
StrCpy(t.HubName, sizeof(t.HubName), hubname);
|
|
|
|
if(StrCmp(cmd, "ENABLE") == 0)
|
|
{
|
|
retcode = StEnableSecureNAT(context->Admin, &t);
|
|
}
|
|
else
|
|
{
|
|
retcode = StDisableSecureNAT(context->Admin, &t);
|
|
}
|
|
|
|
if(retcode != ERR_NO_ERROR)
|
|
{
|
|
return WuErrorPage(retcode);
|
|
}
|
|
|
|
Format(tmp, sizeof(tmp), "%s?HUB=%s&KEY=%s", WP_SECURENAT, hubname, sessionkey);
|
|
return WuRedirectPage(tmp);
|
|
}
|
|
// Set the SecureNAT options
|
|
else if(StrCmp(cmd, "SAVE") == 0)
|
|
{
|
|
char tmp[MAX_SIZE];
|
|
VH_OPTION t;
|
|
|
|
Zero(&t, sizeof(t));
|
|
StrCpy(t.HubName, sizeof(t.HubName), hubname);
|
|
|
|
// Configure the a virtual host
|
|
StrToMac(t.MacAddress, (char*)StrMapSearch(params, "HOSTMAC"));
|
|
StrToIP(&t.Ip, (char*)StrMapSearch(params, "HOSTIP"));
|
|
StrToIP(&t.Mask, (char*)StrMapSearch(params, "HOSTMASK"));
|
|
|
|
// Configure the virtual NAT function
|
|
t.UseNat = (StrCmp((char*)StrMapSearch(params, "NATCHECK"), "on") == 0);
|
|
t.Mtu = ToInt((char*)StrMapSearch(params, "NATMTU"));
|
|
t.NatTcpTimeout = ToInt((char*)StrMapSearch(params, "NATTCPTIMEOUT"));
|
|
t.NatUdpTimeout = ToInt((char*)StrMapSearch(params, "NATUDPTIMEOUT"));
|
|
t.SaveLog = (StrCmp((char*)StrMapSearch(params, "NATSAVELOG"), "on") == 0);
|
|
|
|
// Configure the virtual DHCP server function
|
|
t.UseDhcp = (StrCmp((char*)StrMapSearch(params, "DHCPCHECK"), "on") == 0);
|
|
StrToIP(&t.DhcpLeaseIPStart, (char*)StrMapSearch(params, "DHCPIPS"));
|
|
StrToIP(&t.DhcpLeaseIPEnd, (char*)StrMapSearch(params, "DHCPIPE"));
|
|
StrToIP(&t.DhcpSubnetMask, (char*)StrMapSearch(params, "DHCPMASK"));
|
|
t.DhcpExpireTimeSpan = ToInt((char*)StrMapSearch(params, "DHCPEXPIRE"));
|
|
StrToIP(&t.DhcpGatewayAddress, (char*)StrMapSearch(params, "DHCPGW"));
|
|
StrToIP(&t.DhcpDnsServerAddress, (char*)StrMapSearch(params, "DHCPDNS"));
|
|
StrCpy(t.DhcpDomainName, sizeof(t.DhcpDomainName), (char*)StrMapSearch(params, "DHCPDOMAIN"));
|
|
|
|
retcode = StSetSecureNATOption(context->Admin, &t);
|
|
if(retcode == ERR_NO_ERROR)
|
|
{
|
|
Format(tmp, sizeof(tmp), "%s?HUB=%s&KEY=%s", WP_SECURENAT, hubname, sessionkey);
|
|
return WuRedirectPage(tmp);
|
|
}
|
|
return WuErrorPage(retcode);
|
|
}
|
|
|
|
buf = WuUniReadFile("|"WP_SECURENAT);
|
|
|
|
// Get the enable / disable state of the current SecureNAT
|
|
{
|
|
RPC_HUB_STATUS t;
|
|
Zero(&t, sizeof(&t));
|
|
StrCpy(t.HubName, sizeof(t.HubName), hubname);
|
|
|
|
retcode = StGetHubStatus(context->Admin, &t);
|
|
|
|
if(retcode != ERR_NO_ERROR)
|
|
{
|
|
Free(buf);
|
|
return WuErrorPage(retcode);
|
|
}
|
|
|
|
WuEnableTag(&buf, t.SecureNATEnabled ? L"DISABLESNAT" : L"ENABLESNAT");
|
|
}
|
|
|
|
// Show the advanced settings of the current SecureNAT
|
|
{
|
|
char mac[MAX_SIZE], ip[MAX_SIZE], mask[MAX_SIZE];
|
|
char dhcpips[MAX_SIZE], dhcpipe[MAX_SIZE], dhcpmask[MAX_SIZE];
|
|
char optgw[MAX_SIZE], optdns[MAX_SIZE];
|
|
VH_OPTION t;
|
|
|
|
Zero(&t, sizeof(t));
|
|
StrCpy(t.HubName, sizeof(t.HubName), hubname);
|
|
|
|
retcode = StGetSecureNATOption(context->Admin, &t);
|
|
|
|
|
|
// Configure the virtual interfaces
|
|
MacToStr(mac, sizeof(mac), t.MacAddress);
|
|
IPToStr(ip, sizeof(ip), &t.Ip);
|
|
IPToStr(mask, sizeof(mask), &t.Mask);
|
|
WuUniStrReplace(&buf, L"{HOSTMAC}", mac);
|
|
WuUniStrReplace(&buf, L"{HOSTIP}", ip);
|
|
WuUniStrReplace(&buf, L"{HOSTMASK}", mask);
|
|
|
|
// Configure the Virtual NAT
|
|
WuUniStrReplace(&buf, L"{NATCHECK}", t.UseNat ? "CHECKED" : "");
|
|
WuUniUintReplace(&buf, L"{NATMTU}", t.Mtu);
|
|
WuUniUintReplace(&buf, L"{NATTCPTIMEOUT}", t.NatTcpTimeout);
|
|
WuUniUintReplace(&buf, L"{NATUDPTIMEOUT}", t.NatUdpTimeout);
|
|
|
|
WuUniStrReplace(&buf, L"{NATSAVELOG}", t.SaveLog ? "CHECKED" : "");
|
|
|
|
// Configure the Virtual DHCP server
|
|
WuUniStrReplace(&buf, L"{DHCPCHECK}", t.UseDhcp ? "CHECKED" : "");
|
|
|
|
IPToStr(dhcpips, sizeof(dhcpips), &t.DhcpLeaseIPStart);
|
|
IPToStr(dhcpipe, sizeof(dhcpipe), &t.DhcpLeaseIPEnd);
|
|
IPToStr(dhcpmask, sizeof(dhcpmask), &t.DhcpSubnetMask);
|
|
WuUniStrReplace(&buf, L"{DHCPIPS}", dhcpips);
|
|
WuUniStrReplace(&buf, L"{DHCPIPE}", dhcpipe);
|
|
WuUniStrReplace(&buf, L"{DHCPMASK}", dhcpmask);
|
|
WuUniUintReplace(&buf, L"{DHCPEXPIRE}", t.DhcpExpireTimeSpan);
|
|
|
|
IPToStr(optgw, sizeof(optgw), &t.DhcpGatewayAddress);
|
|
IPToStr(optdns, sizeof(optdns), &t.DhcpDnsServerAddress);
|
|
WuUniStrReplace(&buf, L"{DHCPGW}", optgw);
|
|
WuUniStrReplace(&buf, L"{DHCPDNS}", optdns);
|
|
WuUniStrReplace(&buf, L"{DHCPDOMAIN}", t.DhcpDomainName);
|
|
}
|
|
|
|
WuUniStrReplace(&buf, L"{LINK_HUB}", WP_HUB);
|
|
WuUniStrReplace(&buf, L"{LINK_SECURENAT}", WP_SECURENAT);
|
|
WuUniStrReplace(&buf, L"{HUBNAME}", hubname);
|
|
WuUniStrReplace(&buf, L"{SESSIONKEY}", sessionkey);
|
|
|
|
return buf;
|
|
}
|
|
|
|
static wchar_t *WpSession(WEBUI *wu, LIST *params)
|
|
{
|
|
char *sessionkey = (char*)StrMapSearch(params, "KEY");
|
|
WU_CONTEXT *context = WuGetContext(wu->Contexts, sessionkey);
|
|
char *hub = (char*)StrMapSearch(params, "HUB");
|
|
char *cmd = (char*)StrMapSearch(params, "CMD");
|
|
|
|
if(context == NULL)
|
|
{
|
|
return WuRedirectPage(WP_LOGIN);
|
|
}
|
|
|
|
if(StrCmp(cmd, "DEL") == 0)
|
|
{
|
|
char *session = (char*)StrMapSearch(params, "SESSION");
|
|
RPC_DELETE_SESSION t;
|
|
UINT retcode;
|
|
char tmp[MAX_SIZE];
|
|
|
|
Zero(&t, sizeof(t));
|
|
StrCpy(t.HubName, sizeof(t.HubName), hub);
|
|
StrCpy(t.Name, sizeof(t.Name), session);
|
|
|
|
retcode = StDeleteSession(context->Admin, &t);
|
|
if(retcode != ERR_NO_ERROR)
|
|
{
|
|
return WuErrorPage(retcode);
|
|
}
|
|
|
|
Format(tmp, sizeof(tmp), "%s?HUB=%s&KEY=%s", WP_SESSION, hub, session);
|
|
return WuRedirectPage(tmp);
|
|
}
|
|
|
|
// Show the session list
|
|
{
|
|
RPC_ENUM_SESSION t;
|
|
UINT retcode;
|
|
|
|
Zero(&t, sizeof(t));
|
|
StrCpy(t.HubName, sizeof(t.HubName), hub);
|
|
|
|
retcode = StEnumSession(context->Admin, &t);
|
|
if(retcode != ERR_NO_ERROR)
|
|
{
|
|
return WuErrorPage(retcode);
|
|
}else{
|
|
wchar_t *buf = WuUniReadFile("|"WP_SESSION);
|
|
wchar_t *tmpl = WuUniGetTemplate(&buf, L"<!--SESSION_TMPL:", L":SESSION_TMPL-->", true);
|
|
UINT i;
|
|
for(i=0; i<t.NumSession; i++){
|
|
RPC_ENUM_SESSION_ITEM *item = &(t.Sessions[i]);
|
|
wchar_t *tmp = CopyUniStr(tmpl);
|
|
|
|
WuUniStrReplace(&tmp, L"{SESSION_NAME}", item->Name);
|
|
WuUniStrReplace(&tmp, L"{SESSION_SERVER}", item->RemoteHostname);
|
|
WuUniStrReplace(&tmp, L"{SESSION_USER}", item->Username);
|
|
WuUniStrReplace(&tmp, L"{SESSION_HOST}", item->Hostname);
|
|
WuUniUintReplace(&tmp, L"{SESSION_TCP}", item->CurrentNumTcp);
|
|
WuUniUint64Replace(&tmp, L"{SESSION_BYTES}", item->PacketSize);
|
|
WuUniUint64Replace(&tmp, L"{SESSION_PKTS}", item->PacketNum);
|
|
WuUniStrReplace(&tmp, L"{SESSION}", item->Name);
|
|
|
|
WuUniInsertBefore(&buf, tmp, L"<!--SESSIONS-->");
|
|
Free(tmp);
|
|
}
|
|
|
|
WuUniStrReplace(&buf, L"{HUBNAME}", hub);
|
|
WuUniStrReplace(&buf, L"{SESSIONKEY}", sessionkey);
|
|
WuUniStrReplace(&buf, L"{LINK_HUB}", WP_HUB);
|
|
WuUniStrReplace(&buf, L"{LINK_SESSION}", WP_SESSION);
|
|
|
|
FreeRpcEnumSession(&t);
|
|
Free(tmpl);
|
|
return buf;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// **** Public interface of the WebUI module
|
|
|
|
// Get the page
|
|
WU_WEBPAGE *WuGetPage(char *target, WEBUI *wu)
|
|
{
|
|
char filename[MAX_SIZE];
|
|
LIST *params;
|
|
wchar_t *(*handler)(WEBUI *wu, LIST *params);
|
|
|
|
// Delete the expired session keys
|
|
WuExpireSessionKey(wu);
|
|
|
|
params = WuAnalyzeTarget(target, filename, sizeof(filename));
|
|
|
|
// Search for the handler corresponding to the URL
|
|
handler = StrMapSearch(wu->PageList, filename);
|
|
|
|
// Call the handler
|
|
if(handler != NULL)
|
|
{
|
|
wchar_t *unitmp;
|
|
WU_WEBPAGE *page;
|
|
unitmp = handler(wu, params);
|
|
WuFreeStrStrMap(params);
|
|
page = WuNewUniWebPage(unitmp);
|
|
Free(unitmp);
|
|
return page;
|
|
}
|
|
|
|
WuFreeStrStrMap(params);
|
|
|
|
// If it missed, try to read the file directly
|
|
if(StartWith(filename, WP_DEFAULT))
|
|
{
|
|
char tmp[MAX_SIZE] = "|";
|
|
BUF *buf;
|
|
WU_WEBPAGE *page;
|
|
|
|
StrCat(tmp, sizeof(tmp), filename);
|
|
buf = ReadDump(tmp);
|
|
if(buf == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
page = WuNewWebPage(buf->Buf, buf->Size, filename);
|
|
FreeBuf(buf);
|
|
return page;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// Start the WebUI
|
|
WEBUI *WuNewWebUI(CEDAR *cedar)
|
|
{
|
|
WEBUI *wu = (WEBUI*)Malloc(sizeof(WEBUI));
|
|
int i;
|
|
|
|
wu->Cedar = cedar;
|
|
|
|
wu->PageList = NewStrMap();
|
|
for(i=0;i<sizeof(wu_pages)/sizeof(STRMAP_ENTRY);i++)
|
|
{
|
|
Add(wu->PageList, &wu_pages[i]);
|
|
}
|
|
|
|
wu->Contexts = NewStrMap();
|
|
|
|
return wu;
|
|
}
|
|
|
|
// Release the WebUI
|
|
bool WuFreeWebUI(WEBUI *wu)
|
|
{
|
|
UINT i;
|
|
|
|
if(wu == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for(i=0; i<LIST_NUM(wu->Contexts); i++)
|
|
{
|
|
STRMAP_ENTRY *se = LIST_DATA(wu->Contexts, i);
|
|
Free(se->Name);
|
|
WuFreeContext((WU_CONTEXT*)se->Value);
|
|
Free(se);
|
|
}
|
|
ReleaseList(wu->Contexts);
|
|
|
|
ReleaseList(wu->PageList);
|
|
Free(wu);
|
|
return true;
|
|
}
|
|
|
|
void WuFreeWebPage(WU_WEBPAGE *page)
|
|
{
|
|
if(page == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
FreeHttpHeader(page->header);
|
|
Free(page->data);
|
|
Free(page);
|
|
}
|
|
|
|
// **** Module local utility functions
|
|
|
|
// Initialize the context
|
|
static WU_CONTEXT *WuNewContext(WEBUI *wu, char *hubname)
|
|
{
|
|
WU_CONTEXT *context = (WU_CONTEXT*)Malloc(sizeof(WU_CONTEXT));
|
|
|
|
if(StrLen(hubname) == 0)
|
|
{
|
|
hubname=NULL;
|
|
}
|
|
context->Admin = (ADMIN*)ZeroMalloc(sizeof(ADMIN));
|
|
context->Admin->HubName = hubname != NULL ? CopyStr(hubname) : NULL;
|
|
context->Admin->Server = wu->Cedar->Server;
|
|
context->Admin->ServerAdmin = hubname == NULL ? true: false;
|
|
context->Admin->Rpc = (RPC*)ZeroMalloc(sizeof(RPC));
|
|
StrCpy(context->Admin->Rpc->Name, sizeof(context->Admin->Rpc->Name), "WEBUI");
|
|
context->Admin->Rpc->Param = context->Admin;
|
|
context->Admin->Rpc->ServerAdminMode = context->Admin->ServerAdmin;
|
|
context->Admin->Rpc->ServerMode = true;
|
|
context->Admin->Rpc->IsVpnServer = true;
|
|
context->Admin->Rpc->Lock = NewLock();
|
|
context->Admin->LogFileList = NULL;
|
|
|
|
context->ExpireDate = Tick64() + WU_CONTEXT_EXPIRE;
|
|
|
|
return context;
|
|
}
|
|
|
|
// Release the context
|
|
static void WuFreeContext(WU_CONTEXT *context)
|
|
{
|
|
DeleteLock(context->Admin->Rpc->Lock);
|
|
Free(context->Admin->Rpc);
|
|
Free(context->Admin->HubName);
|
|
Free(context->Admin);
|
|
Free(context);
|
|
}
|
|
|
|
// Create a WebPage structure from the Unicode string
|
|
static WU_WEBPAGE *WuNewUniWebPage(wchar_t *content)
|
|
{
|
|
WU_WEBPAGE *ret;
|
|
|
|
if(content == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
ret = (WU_WEBPAGE*)Malloc(sizeof(WU_WEBPAGE));
|
|
ret->size = CalcUniToUtf8(content);
|
|
ret->data = (char*)Malloc(ret->size);
|
|
UniToUtf8(ret->data, ret->size, content);
|
|
|
|
ret->header = NewHttpHeader("HTTP/1.1", "202", "OK");
|
|
AddHttpValue(ret->header, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE4));
|
|
AddHttpValue(ret->header, NewHttpValue("Connection", "Keep-Alive"));
|
|
AddHttpValue(ret->header, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Generate the WebPage structure from the raw data
|
|
static WU_WEBPAGE *WuNewWebPage(char *content, UINT size, char *filename)
|
|
{
|
|
WU_WEBPAGE *ret;
|
|
|
|
if(content == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
ret = (WU_WEBPAGE*)Malloc(sizeof(WU_WEBPAGE));
|
|
ret->size = size;
|
|
ret->data = (char*)Malloc(size);
|
|
Copy(ret->data, content, size);
|
|
|
|
ret->header = NewHttpHeader("HTTP/1.1", "202", "OK");
|
|
AddHttpValue(ret->header, NewHttpValue("Connection", "Keep-Alive"));
|
|
AddHttpValue(ret->header, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));
|
|
|
|
if(EndWith(filename, "jpg"))
|
|
{
|
|
AddHttpValue(ret->header, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE3));
|
|
}
|
|
AddHttpValue(ret->header, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE4));
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Return an error page
|
|
static wchar_t *WuErrorPage(UINT errorcode)
|
|
{
|
|
wchar_t *buf = WuUniReadFile("|"WP_ERROR);
|
|
wchar_t tmp[MAX_SIZE];
|
|
UniFormat(tmp, sizeof(tmp), L"%d\n<H2>%s</H2>", errorcode, GetUniErrorStr(errorcode));
|
|
WuUniReplace(&buf, L"ERRMSG", tmp);
|
|
return buf;
|
|
}
|
|
|
|
// Redirect
|
|
static wchar_t *WuRedirectPage(char *url)
|
|
{
|
|
wchar_t *buf = WuUniReadFile("|"WP_REDIRECT);
|
|
wchar_t tmp[MAX_SIZE];
|
|
StrToUni(tmp, sizeof(tmp), url);
|
|
WuUniReplace(&buf, L"REDIRECT_TO", tmp);
|
|
return buf;
|
|
}
|
|
|
|
// Analyse the URL
|
|
static LIST *WuAnalyzeTarget(char *target,char *filename, UINT size)
|
|
{
|
|
char *start, tmp;
|
|
|
|
if(target == NULL || filename == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// Process the absolute path specification
|
|
if(StartWith(target,"http://"))
|
|
{
|
|
// Skip http://
|
|
target += 7;
|
|
|
|
// Skip the host name portion
|
|
while(*target != '/' && *target != '\0')
|
|
{
|
|
target ++;
|
|
}
|
|
|
|
// Error if the "/" isn't included after "http://"
|
|
if(*target == '\0')
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
target++;
|
|
}
|
|
|
|
// Unescape
|
|
// (not implemented)
|
|
|
|
// Extract the file name portion
|
|
start = target;
|
|
while(*target != '?' && *target != '\0')
|
|
{
|
|
target ++;
|
|
}
|
|
tmp = *target;
|
|
*target = '\0';
|
|
StrCpy(filename, size, start);
|
|
*target = tmp;
|
|
|
|
// Interpret if there are parameters
|
|
if(*target == '?')
|
|
{
|
|
LIST *params = NewStrMap();
|
|
UINT i;
|
|
TOKEN_LIST *tl;
|
|
target++;
|
|
tl =ParseToken(target,"&");
|
|
for(i=0;i<tl->NumTokens;i++)
|
|
{
|
|
char *token = tl->Token[i];
|
|
char *body = token;
|
|
STRMAP_ENTRY *newentry = (STRMAP_ENTRY*)Malloc(sizeof(STRMAP_ENTRY));
|
|
|
|
while(*body != '=' && *body != '\0')
|
|
{
|
|
*body ++;
|
|
}
|
|
if(*body == '=')
|
|
{
|
|
*body = '\0';
|
|
body++;
|
|
}
|
|
newentry->Name = CopyStr(token);
|
|
newentry->Value = CopyStr(body);
|
|
Add(params, newentry);
|
|
// Debug("PARAMS: %s : %s\n",token,body);
|
|
}
|
|
FreeToken(tl);
|
|
return params;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// Release the parameter list
|
|
static void WuFreeStrStrMap(LIST *params)
|
|
{
|
|
UINT i;
|
|
|
|
if(params == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for(i=0; i<LIST_NUM(params); i++)
|
|
{
|
|
STRMAP_ENTRY *e = (STRMAP_ENTRY*)LIST_DATA(params, i);
|
|
Free(e->Name);
|
|
Free(e->Value);
|
|
Free(e);
|
|
}
|
|
ReleaseList(params);
|
|
}
|
|
|
|
// Read the UTF-8 file and convert as an Unicode string
|
|
static wchar_t *WuUniReadFile(char *filename)
|
|
{
|
|
IO *io;
|
|
UINT size, usize;
|
|
BYTE *utf8;
|
|
wchar_t *wchars;
|
|
|
|
// Validate arguments
|
|
if (filename == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
io = FileOpen(filename, false);
|
|
if (io == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// Load the file
|
|
size = FileSize(io);
|
|
utf8 = (BYTE*)Malloc(size);
|
|
FileRead(io, (void*)utf8, size);
|
|
FileClose(io);
|
|
|
|
usize = CalcUtf8ToUni(utf8, size);
|
|
wchars = (wchar_t*)ZeroMalloc(usize+sizeof(wchar_t));
|
|
Utf8ToUni(wchars, usize, utf8, size);
|
|
Free(utf8);
|
|
|
|
return wchars;
|
|
}
|
|
|
|
// Replace string (with memory reallocation)
|
|
static void WuUniReplace(wchar_t **buf, wchar_t *from, wchar_t *to)
|
|
{
|
|
UINT dstsize;
|
|
wchar_t *oldbuf;
|
|
|
|
if(buf == NULL || from == NULL || to == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
oldbuf = *buf;
|
|
|
|
dstsize = (UniCalcReplaceStrEx(*buf, from, to, true) + 1) * sizeof(wchar_t);
|
|
*buf = (wchar_t*)Malloc(dstsize);
|
|
UniReplaceStr(*buf, dstsize, oldbuf, from, to);
|
|
Free(oldbuf);
|
|
}
|
|
|
|
// Insert the string in front of a specified pattern
|
|
static void WuUniInsertBefore(wchar_t **buf, wchar_t *insert, wchar_t *before)
|
|
{
|
|
UINT tmpsize;
|
|
wchar_t *tmp;
|
|
|
|
if(buf == NULL || insert == NULL || before == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
tmpsize = (UniStrLen(insert)+UniStrLen(before)+1)*sizeof(wchar_t);
|
|
tmp = (wchar_t*)Malloc(tmpsize);
|
|
UniStrCpy(tmp, tmpsize, insert);
|
|
UniStrCat(tmp, tmpsize, before);
|
|
WuUniReplace(buf, before, tmp);
|
|
Free(tmp);
|
|
}
|
|
|
|
// Uncomment the tag specified by the keyword
|
|
static void WuEnableTag(wchar_t **buf, wchar_t *keyword)
|
|
{
|
|
wchar_t tmp[MAX_SIZE];
|
|
if(buf == NULL || keyword == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UniFormat(tmp, sizeof(tmp), L"!--%s", keyword);
|
|
WuUniReplace(buf, tmp, L"");
|
|
|
|
UniFormat(tmp, sizeof(tmp), L"%s--", keyword);
|
|
WuUniReplace(buf, tmp, L"");
|
|
return;
|
|
}
|
|
|
|
// Generate a session key
|
|
static char *WuNewSessionKey()
|
|
{
|
|
char tmp[MD5_SIZE], *ret;
|
|
UINT size;
|
|
Rand(tmp, sizeof(tmp));
|
|
size = sizeof(tmp)*2+1;
|
|
ret = Malloc(size);
|
|
BinToStr(ret, size, tmp, sizeof(tmp));
|
|
return ret;
|
|
}
|
|
|
|
// Replace the Unicode pattern in Unicode string with ASCII string
|
|
static void WuUniStrReplace(wchar_t **buf, wchar_t *from, char *to)
|
|
{
|
|
UINT unisize;
|
|
wchar_t *tmp;
|
|
|
|
if(buf == NULL || *buf == NULL || from == NULL || to == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
unisize = CalcStrToUni(to);
|
|
tmp = (wchar_t*)Malloc(unisize);
|
|
StrToUni(tmp, unisize, to);
|
|
WuUniReplace(buf, from, tmp);
|
|
Free(tmp);
|
|
}
|
|
|
|
// Extract the template surrounded by specified Unicode string from Unicode string
|
|
static wchar_t *WuUniGetTemplate(wchar_t **str, wchar_t *start, wchar_t *end, bool erase)
|
|
{
|
|
UINT startidx, endidx, len, size, i;
|
|
wchar_t *ret;
|
|
|
|
if(str == NULL || *str == NULL || start == NULL || end == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
startidx = UniSearchStr(*str, start, 0);
|
|
if(startidx == INFINITE)
|
|
{
|
|
return NULL;
|
|
}
|
|
startidx += UniStrLen(start);
|
|
|
|
endidx = UniSearchStr(*str, end, startidx);
|
|
if(endidx == INFINITE)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
len = endidx - startidx;
|
|
size = (len + 1) * sizeof(wchar_t);
|
|
ret = (wchar_t*)Malloc(size);
|
|
for(i=0; i<len; i++)
|
|
{
|
|
ret[i] = (*str)[startidx + i];
|
|
}
|
|
ret[i] = 0;
|
|
|
|
if(erase)
|
|
{
|
|
wchar_t tmp[MAX_SIZE*10];
|
|
UniFormat(tmp, sizeof(tmp), L"%s%s%s", start, ret, end);
|
|
WuUniReplace(str, tmp, L"");
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// Replace the Unicode pattern in the Unicode string with the UINT number
|
|
static void WuUniUintReplace(wchar_t **buf, wchar_t *key, UINT num)
|
|
{
|
|
wchar_t tmp[MAX_SIZE];
|
|
UniFormat(tmp, sizeof(tmp), L"%d", num);
|
|
WuUniReplace(buf, key, tmp);
|
|
}
|
|
|
|
// Replace the Unicode pattern in the Unicode string with the UINT64 number
|
|
static void WuUniUint64Replace(wchar_t **buf, wchar_t *key, UINT64 num)
|
|
{
|
|
wchar_t tmp[MAX_SIZE];
|
|
UniFormat(tmp, sizeof(tmp), L"%I64d", num);
|
|
WuUniReplace(buf, key, tmp);
|
|
}
|
|
|
|
// Copy the Unicode string until the appearance of the specified character (escapable with '\')
|
|
static wchar_t *WuUniCopyStrTill(wchar_t *str, wchar_t delimiter, wchar_t **ret){
|
|
UINT num = 0, i;
|
|
wchar_t *next = str;
|
|
wchar_t *ptr = str;
|
|
|
|
// Count the number of characters to copy
|
|
while(*next)
|
|
{
|
|
if(*next==L'\\')
|
|
{
|
|
next++;
|
|
if(*next == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(*next == delimiter)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
next++;
|
|
num++;
|
|
}
|
|
|
|
// Allocate the memory and copy the string
|
|
*ret = (wchar_t*)Malloc((num+1)*sizeof(wchar_t));
|
|
for(i=0;i<num;i++)
|
|
{
|
|
if(*ptr == L'\\')
|
|
{
|
|
ptr++;
|
|
}
|
|
(*ret)[i] = *ptr;
|
|
ptr++;
|
|
}
|
|
(*ret)[num]=0;
|
|
|
|
// Return a pointer to the next to the delimiter or the end of the string
|
|
return *next ? next+1 : next;
|
|
}
|
|
|
|
// Create a string table from Unicode string
|
|
static LIST *WuUniMakeTable(wchar_t *def)
|
|
{
|
|
LIST *table;
|
|
STRMAP_ENTRY *entry;
|
|
|
|
if(def==NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
table = NewStrMap();
|
|
while(*def)
|
|
{
|
|
wchar_t *keytmp;
|
|
UINT keylen;
|
|
entry = (STRMAP_ENTRY*)Malloc(sizeof(STRMAP_ENTRY));
|
|
def = WuUniCopyStrTill(def, L':', &keytmp);
|
|
keylen = CalcUniToStr(keytmp);
|
|
entry->Name = (char*)Malloc(keylen);
|
|
UniToStr(entry->Name, keylen, keytmp);
|
|
def = WuUniCopyStrTill(def, L',', (wchar_t**)&(entry->Value));
|
|
Add(table, entry);
|
|
Free(keytmp);
|
|
}
|
|
return table;
|
|
}
|
|
|
|
// Extract the template from Unicode string, and create a string table from it
|
|
static LIST *WuUniMakeTableFromTemplate(wchar_t **str, wchar_t *start, wchar_t *end)
|
|
{
|
|
wchar_t *tmpl = WuUniGetTemplate(str, start, end, true);
|
|
LIST *ret = WuUniMakeTable(tmpl);
|
|
Free(tmpl);
|
|
return ret;
|
|
}
|
|
|
|
// Delete the expired session key
|
|
static void WuExpireSessionKey(WEBUI *wu)
|
|
{
|
|
LIST *Expired = NewList(NULL);
|
|
UINT i;
|
|
|
|
LockList(wu->Contexts);
|
|
|
|
for(i=0; i<LIST_NUM(wu->Contexts); i++)
|
|
{
|
|
STRMAP_ENTRY *entry = (STRMAP_ENTRY*)LIST_DATA(wu->Contexts, i);
|
|
WU_CONTEXT *context = (WU_CONTEXT*)entry->Value;
|
|
if(context->ExpireDate < Tick64())
|
|
{
|
|
Add(Expired, entry);
|
|
}
|
|
}
|
|
|
|
for(i=0; i<LIST_NUM(Expired); i++)
|
|
{
|
|
STRMAP_ENTRY *entry = LIST_DATA(Expired, i);
|
|
Delete(wu->Contexts, entry);
|
|
Free(entry->Name);
|
|
WuFreeContext(entry->Value);
|
|
Free(entry);
|
|
}
|
|
ReleaseList(Expired);
|
|
|
|
UnlockList(wu->Contexts);
|
|
}
|
|
|
|
// Get the context, and extend its expiration date
|
|
static WU_CONTEXT *WuGetContext(LIST *contexts, char *sessionkey)
|
|
{
|
|
WU_CONTEXT *ret = StrMapSearch(contexts, sessionkey);
|
|
if(ret != NULL)
|
|
{
|
|
ret->ExpireDate = Tick64() + WU_CONTEXT_EXPIRE;
|
|
}
|
|
return ret;
|
|
}
|