// SoftEther VPN Source Code - Developer Edition Master Branch // Cedar Communication Module // Account.c // Account Manager #include "Account.h" #include "Hub.h" #include "Layer3.h" #include "Proto_PPP.h" #include "Mayaqua/Internat.h" #include "Mayaqua/Kernel.h" #include "Mayaqua/Memory.h" #include "Mayaqua/Object.h" #include "Mayaqua/Str.h" #include "Mayaqua/Table.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 }; // 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) { UINT i, len; char tmp[MAX_SIZE]; // Validate arguments if (name == NULL) { return false; } StrCpy(tmp, sizeof(tmp), name); name = tmp; Trim(name); len = StrLen(name); if (len == 0) { return false; } if (StrCmpi(name, "*") == 0) { return true; } for (i = 0; i < len; i++) { if (IsSafeChar(name[i]) == false && name[i] != '@') { 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); } // 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)); Sha0(dst, b->Buf, b->Size); 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); } // 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 authentication data FreeAuthData(u->AuthType, u->AuthData); if (u->Policy) { // Free policy data Free(u->Policy); } FreeTraffic(u->Traffic); Free(u); } // Free authentication 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); } // Get the MAC address from the user's note string bool GetUserMacAddressFromUserNote(UCHAR *mac, wchar_t *note) { bool ret = false; UINT i; Zero(mac, 6); if (mac == NULL || note == NULL) { return false; } i = UniSearchStrEx(note, USER_MAC_STR_PREFIX, 0, false); if (i != INFINITE) { wchar_t *macstr_start = ¬e[i + UniStrLen(USER_MAC_STR_PREFIX)]; wchar_t macstr2[MAX_SIZE]; UNI_TOKEN_LIST *tokens; UniStrCpy(macstr2, sizeof(macstr2), macstr_start); UniTrim(macstr2); tokens = UniParseToken(macstr2, L" ,/()[]."); if (tokens != NULL) { if (tokens->NumTokens >= 1) { wchar_t *macstr = tokens->Token[0]; if (UniIsEmptyStr(macstr) == false) { char macstr_a[MAX_SIZE]; UniToStr(macstr_a, sizeof(macstr_a), macstr); ret = StrToMac(mac, macstr_a); } } UniFreeToken(tokens); } } return ret; } // Get the static IPv4 address from the user's note string UINT GetUserIPv4AddressFromUserNote32(wchar_t *note) { bool ret = false; UINT ip32 = 0; UINT i = UniSearchStrEx(note, USER_IPV4_STR_PREFIX, 0, false); if (i != INFINITE) { wchar_t *ipv4str_start = ¬e[i + UniStrLen(USER_IPV4_STR_PREFIX)]; wchar_t ipv4str2[MAX_SIZE]; UNI_TOKEN_LIST *tokens; UniStrCpy(ipv4str2, sizeof(ipv4str2), ipv4str_start); UniTrim(ipv4str2); tokens = UniParseToken(ipv4str2, L" ,/()[]"); if (tokens != NULL) { if (tokens->NumTokens >= 1) { wchar_t *ipv4str = tokens->Token[0]; if (UniIsEmptyStr(ipv4str) == false) { char ipv4str_a[MAX_SIZE]; UniToStr(ipv4str_a, sizeof(ipv4str_a), ipv4str); ip32 = StrToIP32(ipv4str_a); } } UniFreeToken(tokens); } } return ip32; }