softether-vpn/src/Cedar/Account.c

1442 lines
29 KiB
C

// SoftEther VPN Source Code - Stable Edition Repository
// Cedar Communication Module
//
// SoftEther VPN Server, Client and Bridge are free software under the Apache License, Version 2.0.
//
// Copyright (c) Daiyuu Nobori.
// Copyright (c) SoftEther VPN Project, University of Tsukuba, Japan.
// Copyright (c) SoftEther Corporation.
// Copyright (c) all contributors on SoftEther VPN project in GitHub.
//
// All Rights Reserved.
//
// http://www.softether.org/
//
// This stable branch is officially managed by Daiyuu Nobori, the owner of SoftEther VPN Project.
// Pull requests should be sent to the Developer Edition Master Repository on https://github.com/SoftEtherVPN/SoftEtherVPN
//
// License: The Apache License, Version 2.0
// https://www.apache.org/licenses/LICENSE-2.0
//
// DISCLAIMER
// ==========
//
// 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.
//
// 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.
//
// READ AND UNDERSTAND THE 'WARNING.TXT' FILE BEFORE USING THIS SOFTWARE.
// SOME SOFTWARE PROGRAMS FROM THIRD PARTIES ARE INCLUDED ON THIS SOFTWARE WITH
// LICENSE CONDITIONS WHICH ARE DESCRIBED ON THE 'THIRD_PARTY.TXT' FILE.
//
//
// 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.
// Account.c
// Account Manager
#include "CedarPch.h"
// Policy items
POLICY_ITEM policy_item[] =
{
// ID, Value, Omittable, Min, Max, Default, Unit name
// Ver 2.0
{0, false, false, 0, 0, 0, NULL}, // Access
{1, false, false, 0, 0, 0, NULL}, // DHCPFilter
{2, false, false, 0, 0, 0, NULL}, // DHCPNoServer
{3, false, false, 0, 0, 0, NULL}, // DHCPForce
{4, false, false, 0, 0, 0, NULL}, // NoBridge
{5, false, false, 0, 0, 0, NULL}, // NoRouting
{6, false, false, 0, 0, 0, NULL}, // CheckMac
{7, false, false, 0, 0, 0, NULL}, // CheckIP
{8, false, false, 0, 0, 0, NULL}, // ArpDhcpOnly
{9, false, false, 0, 0, 0, NULL}, // PrivacyFilter
{10, false, false, 0, 0, 0, NULL}, // NoServer
{11, false, false, 0, 0, 0, NULL}, // NoBroadcastLimiter
{12, false, false, 0, 0, 0, NULL}, // MonitorPort
{13, true, false, 1, 32, 32, "POL_INT_COUNT"}, // MaxConnection
{14, true, false, 5, 60, 20, "POL_INT_SEC"}, // TimeOut
{15, true, true, 1, 65535, 0, "POL_INT_COUNT"}, // MaxMac
{16, true, true, 1, 65535, 0, "POL_INT_COUNT"}, // MaxIP
{17, true, true, 1, 4294967295UL, 0, "POL_INT_BPS"}, // MaxUpload
{18, true, true, 1, 4294967295UL, 0, "POL_INT_BPS"}, // MaxDownload
{19, false, false, 0, 0, 0, NULL}, // FixPassword
{20, true, true, 1, 65535, 0, "POL_INT_COUNT"}, // MultiLogins
{21, false, false, 0, 0, 0, NULL}, // NoQoS
// Ver 3.0
{22, false, false, 0, 0, 0, NULL}, // RSandRAFilter
{23, false, false, 0, 0, 0, NULL}, // RAFilter
{24, false, false, 0, 0, 0, NULL}, // DHCPv6Filter
{25, false, false, 0, 0, 0, NULL}, // DHCPv6NoServer
{26, false, false, 0, 0, 0, NULL}, // NoRoutingV6
{27, false, false, 0, 0, 0, NULL}, // CheckIPv6
{28, false, false, 0, 0, 0, NULL}, // NoServerV6
{29, true, true, 1, 65535, 0, "POL_INT_COUNT"}, // MaxIPv6
{30, false, false, 0, 0, 0, NULL}, // NoSavePassword
{31, true, true, 1, 4294967295UL, 0, "POL_INT_SEC"}, // AutoDisconnect
{32, false, false, 0, 0, 0, NULL}, // FilterIPv4
{33, false, false, 0, 0, 0, NULL}, // FilterIPv6
{34, false, false, 0, 0, 0, NULL}, // FilterNonIP
{35, false, false, 0, 0, 0, NULL}, // NoIPv6DefaultRouterInRA
{36, false, false, 0, 0, 0, NULL}, // NoIPv6DefaultRouterInRAWhenIPv6
{37, true, true, 1, 4095, 0, "POL_INT_VLAN"}, // VLanId
};
// Normalize policy name
char *NormalizePolicyName(char *name)
{
// Validate arguments
if (name == NULL)
{
return NULL;
}
return PolicyIdToStr(PolicyStrToId(name));
}
// Format policy value
void FormatPolicyValue(wchar_t *str, UINT size, UINT id, UINT value)
{
POLICY_ITEM *p;
// Validate arguments
if (str == NULL)
{
return;
}
p = GetPolicyItem(id);
if (p->TypeInt == false)
{
// bool type
if (value == 0)
{
UniStrCpy(str, size, L"No");
}
else
{
UniStrCpy(str, size, L"Yes");
}
}
else
{
// int type
if (value == 0 && p->AllowZero)
{
UniStrCpy(str, size, _UU("CMD_NO_SETTINGS"));
}
else
{
UniFormat(str, size, _UU(p->FormatStr), value);
}
}
}
// Get description string for range of the policy value
void GetPolicyValueRangeStr(wchar_t *str, UINT size, UINT id)
{
POLICY_ITEM *p;
// Validate arguments
if (str == NULL)
{
return;
}
p = GetPolicyItem(id);
if (p->TypeInt == false)
{
// bool type
UniStrCpy(str, size, _UU("CMD_PolicyList_Range_Bool"));
}
else
{
wchar_t *tag;
wchar_t tmp1[256], tmp2[256];
// int type
if (p->AllowZero)
{
tag = _UU("CMD_PolicyList_Range_Int_2");
}
else
{
tag = _UU("CMD_PolicyList_Range_Int_1");
}
UniFormat(tmp1, sizeof(tmp1), _UU(p->FormatStr), p->MinValue);
UniFormat(tmp2, sizeof(tmp2), _UU(p->FormatStr), p->MaxValue);
UniFormat(str, size, tag, tmp1, tmp2);
}
}
// Get a policy item for id
POLICY_ITEM *GetPolicyItem(UINT id)
{
return &policy_item[id];
}
// Does cascade connection support the specified policy?
bool PolicyIsSupportedForCascade(UINT i)
{
if (i == 0 || i == 4 || i == 5 || i == 12 || i == 13 ||
i == 14 || i == 19 || i == 20 || i == 21 || i == 26 || i == 30 || i == 31 || i == 36)
{
// These items are not supported by cascade connection.
return false;
}
return true;
}
// Get policy name
char *PolicyIdToStr(UINT i)
{
switch (i)
{
// Ver 2.0
case 0: return "Access";
case 1: return "DHCPFilter";
case 2: return "DHCPNoServer";
case 3: return "DHCPForce";
case 4: return "NoBridge";
case 5: return "NoRouting";
case 6: return "CheckMac";
case 7: return "CheckIP";
case 8: return "ArpDhcpOnly";
case 9: return "PrivacyFilter";
case 10: return "NoServer";
case 11: return "NoBroadcastLimiter";
case 12: return "MonitorPort";
case 13: return "MaxConnection";
case 14: return "TimeOut";
case 15: return "MaxMac";
case 16: return "MaxIP";
case 17: return "MaxUpload";
case 18: return "MaxDownload";
case 19: return "FixPassword";
case 20: return "MultiLogins";
case 21: return "NoQoS";
// Ver 3.0
case 22: return "RSandRAFilter";
case 23: return "RAFilter";
case 24: return "DHCPv6Filter";
case 25: return "DHCPv6NoServer";
case 26: return "NoRoutingV6";
case 27: return "CheckIPv6";
case 28: return "NoServerV6";
case 29: return "MaxIPv6";
case 30: return "NoSavePassword";
case 31: return "AutoDisconnect";
case 32: return "FilterIPv4";
case 33: return "FilterIPv6";
case 34: return "FilterNonIP";
case 35: return "NoIPv6DefaultRouterInRA";
case 36: return "NoIPv6DefaultRouterInRAWhenIPv6";
case 37: return "VLanId";
}
return NULL;
}
// Get policy id for name
UINT PolicyStrToId(char *name)
{
UINT i;
// Validate arguments
if (name == NULL)
{
return INFINITE;
}
for (i = 0;i < NUM_POLICY_ITEM;i++)
{
if (StartWith(PolicyIdToStr(i), name))
{
return i;
}
}
return INFINITE;
}
// Get number of policies
UINT PolicyNum()
{
return NUM_POLICY_ITEM;
}
// Check the name is valid for account name
bool IsUserName(char *name)
{
char tmp[MAX_SIZE];
// Validate arguments
if (name == NULL)
{
return false;
}
StrCpy(tmp, sizeof(tmp), name);
name = tmp;
Trim(name);
if (StrLen(name) == 0)
{
return false;
}
if (StrCmpi(name, "*") == 0)
{
return true;
}
if (IsSafeStr(name) == false)
{
return false;
}
if (StrCmpi(name, "link") == 0)
{
return false;
}
if (StrCmpi(name, LINK_USER_NAME) == 0)
{
return false;
}
if (StartWith(name, L3_USERNAME))
{
return false;
}
if (StrCmpi(name, LINK_USER_NAME_PRINT) == 0)
{
return false;
}
if (StrCmpi(name, SNAT_USER_NAME) == 0)
{
return false;
}
if (StrCmpi(name, SNAT_USER_NAME_PRINT) == 0)
{
return false;
}
if (StrCmpi(name, BRIDGE_USER_NAME) == 0)
{
return false;
}
if (StrCmpi(name, BRIDGE_USER_NAME_PRINT) == 0)
{
return false;
}
if (StrCmpi(name, ADMINISTRATOR_USERNAME) == 0)
{
return false;
}
return true;
}
// Get policy title
wchar_t *GetPolicyTitle(UINT id)
{
char tmp[MAX_SIZE];
Format(tmp, sizeof(tmp), "POL_%u", id);
return _UU(tmp);
}
// Get policy description
wchar_t *GetPolicyDescription(UINT id)
{
char tmp[MAX_SIZE];
Format(tmp, sizeof(tmp), "POL_EX_%u", id);
return _UU(tmp);
}
// Clone the policy value
POLICY *ClonePolicy(POLICY *policy)
{
POLICY *ret;
// Validate arguments
if (policy == NULL)
{
return NULL;
}
ret = ZeroMalloc(sizeof(POLICY));
Copy(ret, policy, sizeof(POLICY));
return ret;
}
// Overwrite policy value (If old version data overwrites new version, leave new version value as it is.)
void OverwritePolicy(POLICY **target, POLICY *p)
{
// Validate arguments
if (target == NULL)
{
return;
}
if (p == NULL)
{
// Erase policy
if (*target != NULL)
{
Free(*target);
*target = NULL;
}
}
else
{
if (p->Ver3)
{
// Ver 3
if (*target != NULL)
{
Free(*target);
*target = NULL;
}
*target = ClonePolicy(p);
}
else
{
// Ver 2
if (*target == NULL)
{
*target = ClonePolicy(p);
}
else
{
Copy(*target, p, NUM_POLICY_ITEM_FOR_VER2 * sizeof(UINT));
}
}
}
}
// Set user policy
void SetUserPolicy(USER *u, POLICY *policy)
{
// Validate arguments
if (u == NULL)
{
return;
}
Lock(u->lock);
{
OverwritePolicy(&u->Policy, policy);
}
Unlock(u->lock);
}
// Get user policy
POLICY *GetUserPolicy(USER *u)
{
POLICY *ret;
// Validate arguments
if (u == NULL)
{
return NULL;
}
Lock(u->lock);
{
if (u->Policy == NULL)
{
ret = NULL;
}
else
{
ret = ClonePolicy(u->Policy);
}
}
Unlock(u->lock);
return ret;
}
// Set group policy
void SetGroupPolicy(USERGROUP *g, POLICY *policy)
{
// Validate arguments
if (g == NULL)
{
return;
}
Lock(g->lock);
{
OverwritePolicy(&g->Policy, policy);
}
Unlock(g->lock);
}
// Get group policy
POLICY *GetGroupPolicy(USERGROUP *g)
{
POLICY *ret;
// Validate arguments
if (g == NULL)
{
return NULL;
}
Lock(g->lock);
{
if (g->Policy == NULL)
{
ret = NULL;
}
else
{
ret = ClonePolicy(g->Policy);
}
}
Unlock(g->lock);
return ret;
}
// Get default policy template
POLICY *GetDefaultPolicy()
{
static POLICY def_policy =
{
true,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
32,
20,
0,
0,
0,
0,
false,
0,
false,
false,
false,
false,
false,
false,
false,
false,
0,
false,
0,
false,
false,
false,
false,
false,
};
return &def_policy;
}
// Create a NT authentication data
void *NewNTAuthData(wchar_t *username)
{
AUTHNT *a;
// Validate arguments
a = ZeroMallocEx(sizeof(AUTHNT), true);
a->NtUsername = CopyUniStr(username);
return a;
}
// Create a Radius authentication data
void *NewRadiusAuthData(wchar_t *username)
{
AUTHRADIUS *a;
// Validate arguments
a = ZeroMallocEx(sizeof(AUTHRADIUS), true);
a->RadiusUsername = CopyUniStr(username);
return a;
}
// Create a root certification authentication data
void *NewRootCertAuthData(X_SERIAL *serial, wchar_t *common_name)
{
AUTHROOTCERT *a;
a = ZeroMallocEx(sizeof(AUTHROOTCERT), true);
if (common_name != NULL && UniIsEmptyStr(common_name) == false)
{
a->CommonName = CopyUniStr(common_name);
}
if (serial != NULL && serial->size >= 1)
{
a->Serial = CloneXSerial(serial);
}
return a;
}
// Create an authentication data for user certification
void *NewUserCertAuthData(X *x)
{
AUTHUSERCERT *a;
a = ZeroMalloc(sizeof(AUTHUSERCERT));
a->UserX = CloneX(x);
return a;
}
// Hash the password
void HashPassword(void *dst, char *username, char *password)
{
BUF *b;
char *username_upper;
// Validate arguments
if (dst == NULL || username == NULL || password == NULL)
{
return;
}
b = NewBuf();
username_upper = CopyStr(username);
StrUpper(username_upper);
WriteBuf(b, password, StrLen(password));
WriteBuf(b, username_upper, StrLen(username_upper));
Hash(dst, b->Buf, b->Size, true);
FreeBuf(b);
Free(username_upper);
}
// Create a password authentication data
void *NewPasswordAuthData(char *username, char *password)
{
AUTHPASSWORD *pw;
// Validate arguments
if (username == NULL || password == NULL)
{
return NULL;
}
pw = ZeroMalloc(sizeof(AUTHPASSWORD));
HashPassword(pw->HashedKey, username, password);
GenerateNtPasswordHash(pw->NtLmSecureHash, password);
return pw;
}
// Create a password authentication data for the hashed password
void *NewPasswordAuthDataRaw(UCHAR *hashed_password, UCHAR *ntlm_secure_hash)
{
AUTHPASSWORD *pw;
// Validate arguments
if (hashed_password == NULL)
{
return NULL;
}
pw = ZeroMalloc(sizeof(AUTHPASSWORD));
Copy(pw->HashedKey, hashed_password, SHA1_SIZE);
if (ntlm_secure_hash != NULL)
{
Copy(pw->NtLmSecureHash, ntlm_secure_hash, MD5_SIZE);
}
return pw;
}
// Clone authentication data
void *CopyAuthData(void *authdata, UINT authtype)
{
AUTHPASSWORD *pw = (AUTHPASSWORD *)authdata;
AUTHUSERCERT *usercert = (AUTHUSERCERT *)authdata;
AUTHROOTCERT *rootcert = (AUTHROOTCERT *)authdata;
AUTHRADIUS *radius = (AUTHRADIUS *)authdata;
AUTHNT *nt = (AUTHNT *)authdata;
// Validate arguments
if (authdata == NULL || authtype == AUTHTYPE_ANONYMOUS)
{
return NULL;
}
switch (authtype)
{
case AUTHTYPE_PASSWORD:
{
AUTHPASSWORD *ret = ZeroMalloc(sizeof(AUTHPASSWORD));
Copy(ret, pw, sizeof(AUTHPASSWORD));
return ret;
}
break;
case AUTHTYPE_USERCERT:
{
AUTHUSERCERT *ret = ZeroMalloc(sizeof(AUTHUSERCERT));
ret->UserX = CloneX(usercert->UserX);
return ret;
}
break;
case AUTHTYPE_ROOTCERT:
{
AUTHROOTCERT *ret = ZeroMalloc(sizeof(AUTHROOTCERT));
ret->CommonName = CopyUniStr(rootcert->CommonName);
ret->Serial = CloneXSerial(rootcert->Serial);
return ret;
}
break;
case AUTHTYPE_RADIUS:
{
AUTHRADIUS *ret = ZeroMalloc(sizeof(AUTHRADIUS));
ret->RadiusUsername = UniCopyStr(radius->RadiusUsername);
return ret;
}
break;
case AUTHTYPE_NT:
{
AUTHNT *ret = ZeroMalloc(sizeof(AUTHNT));
ret->NtUsername = UniCopyStr(nt->NtUsername);
return ret;
}
break;
}
return NULL;
}
// Set authentication data to the user
void SetUserAuthData(USER *u, UINT authtype, void *authdata)
{
// Validate arguments
if (u == NULL)
{
return;
}
if (authtype != AUTHTYPE_ANONYMOUS && authdata == NULL)
{
return;
}
Lock(u->lock);
{
if (u->AuthType != AUTHTYPE_ANONYMOUS)
{
if (u->AuthType == AUTHTYPE_PASSWORD && authtype == AUTHTYPE_PASSWORD)
{
AUTHPASSWORD *pw_old = (AUTHPASSWORD *)u->AuthData;
AUTHPASSWORD *pw_new = (AUTHPASSWORD *)authdata;
// Copy NTLM hash for new password from old data, if the password is not changed
// and management tool don't send NTLM hash.
if (Cmp(pw_old->HashedKey, pw_new->HashedKey, SHA1_SIZE) == 0)
{
if (IsZero(pw_new->NtLmSecureHash, MD5_SIZE))
{
Copy(pw_new->NtLmSecureHash, pw_old->NtLmSecureHash, MD5_SIZE);
}
}
}
// Free current authentication data
FreeAuthData(u->AuthType, u->AuthData);
}
// Set new authentication data
u->AuthType = authtype;
u->AuthData = authdata;
}
Unlock(u->lock);
}
// Cumulate group traffic data
void AddGroupTraffic(USERGROUP *g, TRAFFIC *diff)
{
// Validate arguments
if (g == NULL || diff == NULL)
{
return;
}
Lock(g->lock);
{
AddTraffic(g->Traffic, diff);
}
Unlock(g->lock);
}
// Cumulate user traffic data
void AddUserTraffic(USER *u, TRAFFIC *diff)
{
// Validate arguments
if (u == NULL || diff == NULL)
{
return;
}
Lock(u->lock);
{
AddTraffic(u->Traffic, diff);
}
Unlock(u->lock);
}
// Set traffic data for group
void SetGroupTraffic(USERGROUP *g, TRAFFIC *t)
{
// Validate arguments
if (g == NULL)
{
return;
}
Lock(g->lock);
{
if (t != NULL)
{
Copy(g->Traffic, t, sizeof(TRAFFIC));
}
else
{
Zero(g->Traffic, sizeof(TRAFFIC));
}
}
Unlock(g->lock);
}
// Set traffic data for user
void SetUserTraffic(USER *u, TRAFFIC *t)
{
// Validate arguments
if (u == NULL)
{
return;
}
Lock(u->lock);
{
if (t != NULL)
{
Copy(u->Traffic, t, sizeof(TRAFFIC));
}
else
{
Zero(u->Traffic, sizeof(TRAFFIC));
}
}
Unlock(u->lock);
}
// Join the user to the group
void JoinUserToGroup(USER *u, USERGROUP *g)
{
// Validate arguments
if (u == NULL)
{
return;
}
if (g != NULL)
{
// Join
Lock(u->lock);
{
Lock(g->lock);
{
if (u->Group != NULL)
{
// Remove the user from current group first
//
ReleaseGroup(u->Group);
u->Group = NULL;
Free(u->GroupName);
u->GroupName = NULL;
}
// Join the user to the group
u->GroupName = CopyStr(g->Name);
u->Group = g;
AddRef(g->ref);
}
Unlock(g->lock);
}
Unlock(u->lock);
}
else
{
// Withdrawal
Lock(u->lock);
{
if (u->Group != NULL)
{
// Remove the user from current group
ReleaseGroup(u->Group);
u->Group = NULL;
Free(u->GroupName);
u->GroupName = NULL;
}
}
Unlock(u->lock);
}
}
// Validate group name
bool AcIsGroup(HUB *h, char *name)
{
USERGROUP *g;
// Validate arguments
if (h == NULL || name == NULL || NO_ACCOUNT_DB(h))
{
return false;
}
g = AcGetGroup(h, name);
if (g == NULL)
{
return false;
}
ReleaseGroup(g);
return true;
}
// Validate user name
bool AcIsUser(HUB *h, char *name)
{
USER *u;
// Validate arguments
if (h == NULL || name == NULL || NO_ACCOUNT_DB(h))
{
return false;
}
u = AcGetUser(h, name);
if (u == NULL)
{
return false;
}
ReleaseUser(u);
return true;
}
// Get group object
USERGROUP *AcGetGroup(HUB *h, char *name)
{
USERGROUP *g, t;
// Validate arguments
if (h == NULL || name == NULL || NO_ACCOUNT_DB(h))
{
return NULL;
}
t.Name = name;
g = Search(h->HubDb->GroupList, &t);
if (g == NULL)
{
return NULL;
}
AddRef(g->ref);
return g;
}
// Get user object
USER *AcGetUser(HUB *h, char *name)
{
USER *u, t;
// Validate arguments
if (h == NULL || name == NULL || NO_ACCOUNT_DB(h))
{
return NULL;
}
t.Name = name;
u = Search(h->HubDb->UserList, &t);
if (u == NULL)
{
return NULL;
}
AddRef(u->ref);
return u;
}
// Delete the user
bool AcDeleteUser(HUB *h, char *name)
{
USER *u;
// Validate arguments
if (h == NULL || name == NULL)
{
return false;
}
u = AcGetUser(h, name);
if (u == NULL)
{
return false;
}
if (Delete(h->HubDb->UserList, u))
{
ReleaseUser(u);
}
ReleaseUser(u);
return true;
}
// Delete the group
bool AcDeleteGroup(HUB *h, char *name)
{
USERGROUP *g;
UINT i;
// Validate arguments
if (h == NULL || name == NULL)
{
return false;
}
g = AcGetGroup(h, name);
if (g == NULL)
{
return false;
}
if (Delete(h->HubDb->GroupList, g))
{
ReleaseGroup(g);
}
for (i = 0;i < LIST_NUM(h->HubDb->UserList);i++)
{
USER *u = LIST_DATA(h->HubDb->UserList, i);
Lock(u->lock);
{
if (u->Group == g)
{
JoinUserToGroup(u, NULL);
}
}
Unlock(u->lock);
}
ReleaseGroup(g);
return true;
}
// Add new group to the hub
bool AcAddGroup(HUB *h, USERGROUP *g)
{
// Validate arguments
if (h == NULL || g == NULL || NO_ACCOUNT_DB(h))
{
return false;
}
if (LIST_NUM(h->HubDb->GroupList) >= MAX_GROUPS)
{
return false;
}
if (AcIsGroup(h, g->Name) != false)
{
return false;
}
Insert(h->HubDb->GroupList, g);
AddRef(g->ref);
return true;
}
// Add new user in the hub
bool AcAddUser(HUB *h, USER *u)
{
// Validate arguments
if (h == NULL || u == NULL || NO_ACCOUNT_DB(h))
{
return false;
}
if (LIST_NUM(h->HubDb->UserList) >= MAX_USERS)
{
return false;
}
if (AcIsUser(h, u->Name) != false)
{
return false;
}
Insert(h->HubDb->UserList, u);
AddRef(u->ref);
return true;
}
// Release user object (decrease reference counter)
void ReleaseUser(USER *u)
{
// Validate arguments
if (u == NULL)
{
return;
}
if (Release(u->ref) == 0)
{
CleanupUser(u);
}
}
// Cleanup the user object
void CleanupUser(USER *u)
{
// Validate arguments
if (u == NULL)
{
return;
}
DeleteLock(u->lock);
Free(u->Name);
Free(u->RealName);
Free(u->Note);
Free(u->GroupName);
if (u->Group != NULL)
{
ReleaseGroup(u->Group);
}
// Free authntication data
FreeAuthData(u->AuthType, u->AuthData);
if (u->Policy)
{
// Free policy data
Free(u->Policy);
}
FreeTraffic(u->Traffic);
Free(u);
}
// Free authntication data
void FreeAuthData(UINT authtype, void *authdata)
{
AUTHPASSWORD *pw = (AUTHPASSWORD *)authdata;
AUTHUSERCERT *uc = (AUTHUSERCERT *)authdata;
AUTHROOTCERT *rc = (AUTHROOTCERT *)authdata;
AUTHRADIUS *rd = (AUTHRADIUS *)authdata;
AUTHNT *nt = (AUTHNT *)authdata;
// Validate arguments
if (authtype == AUTHTYPE_ANONYMOUS || authdata == NULL)
{
return;
}
switch (authtype)
{
case AUTHTYPE_PASSWORD:
// Password authentication
// Nothing to free
break;
case AUTHTYPE_USERCERT:
// User certification
FreeX(uc->UserX);
break;
case AUTHTYPE_ROOTCERT:
// Root certification
if (rc->Serial != NULL)
{
FreeXSerial(rc->Serial);
}
if (rc->CommonName != NULL)
{
Free(rc->CommonName);
}
break;
case AUTHTYPE_RADIUS:
// Radius authentication
Free(rd->RadiusUsername);
break;
case AUTHTYPE_NT:
// Windows NT authentication
Free(nt->NtUsername);
break;
}
Free(authdata);
}
// Create new user object
USER *NewUser(char *name, wchar_t *realname, wchar_t *note, UINT authtype, void *authdata)
{
USER *u;
// Validate arguments
if (name == NULL || realname == NULL || note == NULL)
{
return NULL;
}
if (authtype != AUTHTYPE_ANONYMOUS && authdata == NULL)
{
return NULL;
}
u = ZeroMalloc(sizeof(USER));
u->lock = NewLock();
u->ref = NewRef();
u->Name = CopyStr(name);
u->RealName = CopyUniStr(realname);
u->Note = CopyUniStr(note);
u->GroupName = NULL;
u->Group = NULL;
u->AuthType = authtype;
u->AuthData = authdata;
u->CreatedTime = SystemTime64();
u->UpdatedTime = SystemTime64();
u->Policy = NULL;
u->Traffic = NewTraffic();
return u;
}
// Release group object (decrease reference counter)
void ReleaseGroup(USERGROUP *g)
{
// Validate arguments
if (g == NULL)
{
return;
}
if (Release(g->ref) == 0)
{
CleanupGroup(g);
}
}
// Cleanup the group object
void CleanupGroup(USERGROUP *g)
{
// Validate arguments
if (g == NULL)
{
return;
}
Free(g->Name);
Free(g->RealName);
Free(g->Note);
if (g->Policy)
{
// Free policy data
Free(g->Policy);
}
FreeTraffic(g->Traffic);
DeleteLock(g->lock);
Free(g);
}
// Create new group object
USERGROUP *NewGroup(char *name, wchar_t *realname, wchar_t *note)
{
USERGROUP *g;
// Validate arguments
if (name == NULL || realname == NULL || note == NULL)
{
return NULL;
}
g = ZeroMalloc(sizeof(USERGROUP));
g->lock = NewLock();
g->ref = NewRef();
g->Name = CopyStr(name);
g->RealName = CopyUniStr(realname);
g->Note = CopyUniStr(note);
g->Policy = NULL;
g->Traffic = NewTraffic();
return g;
}
// Lock the account database for the hub
void AcLock(HUB *h)
{
// Validate arguments
if (h == NULL)
{
return;
}
if (NO_ACCOUNT_DB(h))
{
return;
}
// Lock group list and user list
LockList(h->HubDb->GroupList);
LockList(h->HubDb->UserList);
}
// Unlock the account database for the hub
void AcUnlock(HUB *h)
{
// Validate arguments
if (h == NULL)
{
return;
}
if (NO_ACCOUNT_DB(h))
{
return;
}
// Unlock group list and user list
UnlockList(h->HubDb->UserList);
UnlockList(h->HubDb->GroupList);
}
// Compare group names (for sort)
int CompareGroupName(void *p1, void *p2)
{
USERGROUP *g1, *g2;
// Validate arguments
if (p1 == NULL || p2 == NULL)
{
return 0;
}
g1 = *(USERGROUP **)p1;
g2 = *(USERGROUP **)p2;
if (g1 == NULL || g2 == NULL)
{
return 0;
}
return StrCmpi(g1->Name, g2->Name);
}
// Compare user names (for sort)
int CompareUserName(void *p1, void *p2)
{
USER *u1, *u2;
// Validate arguments
if (p1 == NULL || p2 == NULL)
{
return 0;
}
u1 = *(USER **)p1;
u2 = *(USER **)p2;
if (u1 == NULL || u2 == NULL)
{
return 0;
}
return StrCmpi(u1->Name, u2->Name);
}