// SoftEther VPN Source Code - Developer Edition Master Branch // Cedar Communication Module // © 2020 Nokia // Client.c // Client Manager #include "Client.h" #include "Account.h" #include "Admin.h" #include "Cedar.h" #include "CM.h" #include "Connection.h" #include "IPC.h" #include "Listener.h" #include "Logging.h" #include "Protocol.h" #include "Remote.h" #include "Virtual.h" #include "VLanUnix.h" #include "VLanWin32.h" #include "Win32Com.h" #include "WinUi.h" #include "Mayaqua/Cfg.h" #include "Mayaqua/Encrypt.h" #include "Mayaqua/FileIO.h" #include "Mayaqua/Internat.h" #include "Mayaqua/Kernel.h" #include "Mayaqua/MayaType.h" #include "Mayaqua/Memory.h" #include "Mayaqua/Microsoft.h" #include "Mayaqua/Network.h" #include "Mayaqua/Object.h" #include "Mayaqua/OS.h" #include "Mayaqua/Pack.h" #include "Mayaqua/Secure.h" #include "Mayaqua/Str.h" #include "Mayaqua/Table.h" #include "Mayaqua/Tick64.h" #include "Mayaqua/Win32.h" #include static CLIENT *client = NULL; static LISTENER *cn_listener = NULL; static LOCK *cn_listener_lock = NULL; static UINT64 cn_next_allow = 0; static LOCK *ci_active_sessions_lock = NULL; static UINT ci_num_active_sessions = 0; // In Windows 8 or later, change unreasonable setting of WCM to ensure normal VPN communication void CiDisableWcmNetworkMinimize(CLIENT *c) { #ifdef OS_WIN32 // Validate arguments if (c == NULL) { return; } if (c->Config.NoChangeWcmNetworkSettingOnWindows8) { return; } MsDisableWcmNetworkMinimize(); #endif // OS_WIN32 } // Compare RPC_CLIENT_ENUM_ACCOUNT_ITEM items by last connected date (Reverse) int CiCompareClientAccountEnumItemByLastConnectDateTime(void *p1, void *p2) { RPC_CLIENT_ENUM_ACCOUNT_ITEM *a1, *a2; if (p1 == NULL || p2 == NULL) { return 0; } a1 = *(RPC_CLIENT_ENUM_ACCOUNT_ITEM **)p1; a2 = *(RPC_CLIENT_ENUM_ACCOUNT_ITEM **)p2; if (a1 == NULL || a2 == NULL) { return 0; } if (a1->LastConnectDateTime > a2->LastConnectDateTime) { return -1; } else if (a1->LastConnectDateTime < a2->LastConnectDateTime) { return 1; } return 0; } // If machine changed, reshuffle MAC address for all virtual NIC void CiChangeAllVLanMacAddressIfMachineChanged(CLIENT *c) { UCHAR current_hash_new[SHA1_SIZE]; UCHAR current_hash[SHA1_SIZE]; UCHAR current_hash_old[SHA1_SIZE]; UCHAR saved_hash[SHA1_SIZE]; // Validate arguments if (c == NULL) { return; } #ifdef OS_WIN32 if (MsIsAdmin() == false) { return; } #endif CiGetCurrentMachineHashNew(current_hash_new); CiGetCurrentMachineHash(current_hash); CiGetCurrentMachineHashOld(current_hash_old); if (CiReadLastMachineHash(saved_hash) == false) { CiWriteLastMachineHash(current_hash_new); return; } if (Cmp(saved_hash, current_hash_old, SHA1_SIZE) == 0) { CiWriteLastMachineHash(current_hash_new); return; } if (Cmp(saved_hash, current_hash, SHA1_SIZE) == 0) { CiWriteLastMachineHash(current_hash_new); return; } if (Cmp(saved_hash, current_hash_new, SHA1_SIZE) == 0) { return; } if (CiWriteLastMachineHash(current_hash_new) == false) { return; } CiChangeAllVLanMacAddress(c); } // Get current machine hash (Old) void CiGetCurrentMachineHashOld(void *data) { char name[MAX_PATH]; char *product_id = NULL; // Validate arguments if (data == NULL) { return; } #ifdef OS_WIN32 // Product ID product_id = MsRegReadStr(REG_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "ProductId"); if (product_id == NULL) { product_id = MsRegReadStr(REG_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion", "ProductId"); } StrCpy(name, sizeof(name), product_id); Free(product_id); #else // OS_WIN32 GetMachineName(name, sizeof(name)); #endif // OS_WIN32 Trim(name); StrUpper(name); Sha0(data, name, StrLen(name)); } // Get current machine hash void CiGetCurrentMachineHash(void *data) { char name[MAX_PATH]; char *product_id = NULL; // Validate arguments if (data == NULL) { return; } GetMachineName(name, sizeof(name)); Trim(name); StrUpper(name); Sha0(data, name, StrLen(name)); } // Get current machine hash (without using domain name) void CiGetCurrentMachineHashNew(void *data) { char name[MAX_PATH]; char *p; // Validate arguments if (data == NULL) { return; } GetMachineName(name, sizeof(name)); // Ignore after first period(.) for(p=name; *p; p++) if(*p == '.') *p = 0; Trim(name); StrUpper(name); Sha0(data, name, StrLen(name)); } // Write machine hash bool CiWriteLastMachineHash(void *data) { // Validate arguments if (data == NULL) { return false; } #ifdef OS_WIN32 if (MsRegWriteBinEx(REG_LOCAL_MACHINE, MS_REG_TCP_SETTING_KEY, "LastMachineHash", data, SHA1_SIZE, true) == false) { return false; } return true; #else // OS_WIN32 return false; #endif // OS_WIN32 } // Get previous machine hash bool CiReadLastMachineHash(void *data) { BUF *b = NULL; // Validate arguments if (data == NULL) { return false; } #ifdef OS_WIN32 b = MsRegReadBinEx(REG_LOCAL_MACHINE, MS_REG_TCP_SETTING_KEY, "LastMachineHash", true); if (b == NULL) { return false; } if (b->Size == SHA1_SIZE) { Copy(data, b->Buf, b->Size); FreeBuf(b); return true; } FreeBuf(b); return false; #else // OS_WIN32 return false; #endif // OS_WIN32 } // If the MAC address of each virtual LAN card has been eliminated, set it to random numbers // (measures for Windows 8 -> 8.1 upgrade problem) void CiChangeAllVLanMacAddressIfCleared(CLIENT *c) { #ifdef OS_WIN32 RPC_CLIENT_ENUM_VLAN t; // Validate arguments if (c == NULL) { return; } if (MsIsInfCatalogRequired() == false) { // Not required for other than Windows 8 return; } Zero(&t, sizeof(t)); if (CtEnumVLan(c, &t)) { UINT i; for (i = 0;i < t.NumItem;i++) { RPC_CLIENT_ENUM_VLAN_ITEM *e = t.Items[i]; UCHAR mac[6]; if (StrToMac(mac, e->MacAddress)) { if (mac[0] == 0x00 && mac[1] == 0x00 && mac[2] == 0x01 && mac[3] == 0x00 && mac[4] == 0x00 && mac[5] == 0x01) { char *name = e->DeviceName; RPC_CLIENT_SET_VLAN s; UCHAR mac[6]; GenMacAddress(mac); Zero(&s, sizeof(s)); StrCpy(s.DeviceName, sizeof(s.DeviceName), name); MacToStr(s.MacAddress, sizeof(s.MacAddress), mac); CtSetVLan(c, &s); } } } CiFreeClientEnumVLan(&t); } #endif // OS_WIN32 } // Set the MAC address of all virtual LAN cards to random number void CiChangeAllVLanMacAddress(CLIENT *c) { RPC_CLIENT_ENUM_VLAN t; // Validate arguments if (c == NULL) { return; } Zero(&t, sizeof(t)); if (CtEnumVLan(c, &t)) { UINT i; for (i = 0;i < t.NumItem;i++) { RPC_CLIENT_ENUM_VLAN_ITEM *e = t.Items[i]; UCHAR mac[6]; if (StrToMac(mac, e->MacAddress) && ((mac[0] == 0x00 && mac[1] == 0xAC) || (mac[0] == 0x5E))) { char *name = e->DeviceName; RPC_CLIENT_SET_VLAN s; UCHAR mac[6]; GenMacAddress(mac); Zero(&s, sizeof(s)); StrCpy(s.DeviceName, sizeof(s.DeviceName), name); MacToStr(s.MacAddress, sizeof(s.MacAddress), mac); CtSetVLan(c, &s); } } CiFreeClientEnumVLan(&t); } } // Wait for preparation of notification service to complete void CnWaitForCnServiceReady() { UINT64 start_time = Tick64(); while ((start_time + (UINT64)CLIENT_WAIT_CN_READY_TIMEOUT) >= Tick64()) { if (CnIsCnServiceReady()) { break; } SleepThread(100); } } // Check whether preparation of notification service completed bool CnIsCnServiceReady() { SOCK *s; // Confirm running the notification service if (CnCheckAlreadyExists(false) == false) { // Not running return false; } // Try to connect to the TCP port s = ConnectEx("localhost", CLIENT_NOTIFY_PORT, 500); if (s == NULL) { // The TCP port is not opened return false; } Disconnect(s); ReleaseSock(s); // Running return true; } // Check whether the notification service is already running bool CnCheckAlreadyExists(bool lock) { #ifdef OS_WIN32 return Win32CnCheckAlreadyExists(lock); #else return false; #endif } typedef struct CNC_STATUS_PRINTER_WINDOW_PARAM { THREAD *Thread; SESSION *Session; SOCK *Sock; } CNC_STATUS_PRINTER_WINDOW_PARAM; typedef struct CNC_CONNECT_ERROR_DLG_THREAD_PARAM { SESSION *Session; SOCK *Sock; bool HaltThread; EVENT *Event; } CNC_CONNECT_ERROR_DLG_THREAD_PARAM; // Thread to stop forcibly the Certificate check dialog client void CncCheckCertHaltThread(THREAD *thread, void *param) { CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp = (CNC_CONNECT_ERROR_DLG_THREAD_PARAM *)param; // Validate arguments if (thread == NULL || param == NULL) { return; } while (true) { if (dp->Session->Halt || dp->HaltThread) { break; } Wait(dp->Event, 100); } Disconnect(dp->Sock); } // Show the certification check dialog void CncCheckCert(SESSION *session, UI_CHECKCERT *dlg) { SOCK *s; PACK *p; CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp; THREAD *t; // Validate arguments if (dlg == NULL || session == NULL) { return; } s = CncConnect(); if (s == NULL) { return; } p = NewPack(); PackAddStr(p, "function", "check_cert"); PackAddUniStr(p, "AccountName", dlg->AccountName); PackAddStr(p, "ServerName", dlg->ServerName); PackAddX(p, "x", dlg->x); PackAddX(p, "parent_x", dlg->parent_x); PackAddX(p, "old_x", dlg->old_x); PackAddBool(p, "DiffWarning", dlg->DiffWarning); PackAddBool(p, "Ok", dlg->Ok); PackAddBool(p, "SaveServerCert", dlg->SaveServerCert); SendPack(s, p); FreePack(p); dp = ZeroMalloc(sizeof(CNC_CONNECT_ERROR_DLG_THREAD_PARAM)); dp->Sock = s; dp->Event = NewEvent(); dp->Session = session; t = NewThread(CncCheckCertHaltThread, dp); p = RecvPack(s); if (p != NULL) { dlg->Ok = PackGetBool(p, "Ok"); dlg->DiffWarning = PackGetBool(p, "DiffWarning"); dlg->SaveServerCert = PackGetBool(p, "SaveServerCert"); FreePack(p); } dp->HaltThread = true; Set(dp->Event); WaitThread(t, INFINITE); ReleaseEvent(dp->Event); Free(dp); ReleaseThread(t); Disconnect(s); ReleaseSock(s); } // Smart card signature dialog bool CncSecureSignDlg(SECURE_SIGN *sign) { SOCK *s; PACK *p; bool ret = false; // Validate arguments if (sign == NULL) { return false; } s = CncConnect(); if (s == NULL) { return false; } p = NewPack(); PackAddStr(p, "function", "secure_sign"); OutRpcSecureSign(p, sign); SendPack(s, p); FreePack(p); p = RecvPack(s); if (p != NULL) { ret = PackGetBool(p, "ret"); if (ret) { FreeRpcSecureSign(sign); Zero(sign, sizeof(SECURE_SIGN)); InRpcSecureSign(sign, p); } FreePack(p); } Disconnect(s); ReleaseSock(s); return ret; } // Show the NIC information dialog SOCK *CncNicInfo(UI_NICINFO *info) { SOCK *s; PACK *p; // Validate arguments if (info == NULL) { return NULL; } s = CncConnectEx(200); if (s == NULL) { return NULL; } p = NewPack(); PackAddStr(p, "function", "nicinfo"); PackAddStr(p, "NicName", info->NicName); PackAddUniStr(p, "AccountName", info->AccountName); SendPack(s, p); FreePack(p); return s; } // Close the NIC information dialog void CncNicInfoFree(SOCK *s) { // Validate arguments if (s == NULL) { return; } Disconnect(s); ReleaseSock(s); } // Show the message dialog SOCK *CncMsgDlg(UI_MSG_DLG *dlg) { SOCK *s; PACK *p; char *utf; // Validate arguments if (dlg == NULL) { return NULL; } s = CncConnectEx(200); if (s == NULL) { return NULL; } p = NewPack(); PackAddStr(p, "function", "msg_dialog"); PackAddStr(p, "ServerName", dlg->ServerName); PackAddStr(p, "HubName", dlg->HubName); utf = CopyUniToUtf(dlg->Msg); PackAddData(p, "Msg", utf, StrLen(utf)); Free(utf); SendPack(s, p); FreePack(p); return s; } // Close the message dialog void CndMsgDlgFree(SOCK *s) { // Validate arguments if (s == NULL) { return; } Disconnect(s); ReleaseSock(s); } // Show the password input dialog bool CncPasswordDlg(SESSION *session, UI_PASSWORD_DLG *dlg) { SOCK *s; PACK *p; CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp; THREAD *t; bool ret = false; // Validate arguments if (dlg == NULL || session == NULL) { return false; } s = CncConnect(); if (s == NULL) { Wait(session->HaltEvent, session->RetryInterval); return true; } p = NewPack(); PackAddStr(p, "function", "password_dialog"); PackAddInt(p, "Type", dlg->Type); PackAddStr(p, "Username", dlg->Username); PackAddStr(p, "Password", dlg->Password); PackAddStr(p, "ServerName", dlg->ServerName); PackAddInt(p, "RetryIntervalSec", dlg->RetryIntervalSec); PackAddBool(p, "ProxyServer", dlg->ProxyServer); PackAddBool(p, "AdminMode", dlg->AdminMode); PackAddBool(p, "ShowNoSavePassword", dlg->ShowNoSavePassword); PackAddBool(p, "NoSavePassword", dlg->NoSavePassword); SendPack(s, p); FreePack(p); dp = ZeroMalloc(sizeof(CNC_CONNECT_ERROR_DLG_THREAD_PARAM)); dp->Session = session; dp->Sock = s; dp->Event = NewEvent(); t = NewThread(CncConnectErrorDlgHaltThread, dp); p = RecvPack(s); if (p != NULL) { ret = PackGetBool(p, "ok"); dlg->NoSavePassword = PackGetBool(p, "NoSavePassword"); dlg->ProxyServer = PackGetBool(p, "ProxyServer"); dlg->Type = PackGetInt(p, "Type"); PackGetStr(p, "Username", dlg->Username, sizeof(dlg->Username)); PackGetStr(p, "Password", dlg->Password, sizeof(dlg->Password)); FreePack(p); } dp->HaltThread = true; Set(dp->Event); WaitThread(t, INFINITE); ReleaseEvent(dp->Event); Free(dp); ReleaseThread(t); Disconnect(s); ReleaseSock(s); return ret; } // Thread to stop the connection error dialog client forcibly void CncConnectErrorDlgHaltThread(THREAD *thread, void *param) { CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp = (CNC_CONNECT_ERROR_DLG_THREAD_PARAM *)param; // Validate arguments if (thread == NULL || param == NULL) { return; } while (true) { if (dp->Session->Halt || dp->HaltThread) { break; } Wait(dp->Event, 100); } Disconnect(dp->Sock); } // Show the connection error dialog bool CncConnectErrorDlg(SESSION *session, UI_CONNECTERROR_DLG *dlg) { SOCK *s; PACK *p; CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp; THREAD *t; bool ret = false; // Validate arguments if (dlg == NULL || session == NULL) { return false; } s = CncConnect(); if (s == NULL) { Wait(session->HaltEvent, session->RetryInterval); return true; } p = NewPack(); PackAddStr(p, "function", "connecterror_dialog"); PackAddUniStr(p, "AccountName", dlg->AccountName); PackAddStr(p, "ServerName", dlg->ServerName); PackAddInt(p, "Err", dlg->Err); PackAddInt(p, "CurrentRetryCount", dlg->CurrentRetryCount); PackAddInt(p, "RetryLimit", dlg->RetryLimit); PackAddInt(p, "RetryIntervalSec", dlg->RetryIntervalSec); PackAddBool(p, "HideWindow", dlg->HideWindow); SendPack(s, p); FreePack(p); dp = ZeroMalloc(sizeof(CNC_CONNECT_ERROR_DLG_THREAD_PARAM)); dp->Session = session; dp->Sock = s; dp->Event = NewEvent(); t = NewThread(CncConnectErrorDlgHaltThread, dp); p = RecvPack(s); if (p != NULL) { ret = PackGetBool(p, "ok"); dlg->HideWindow = PackGetBool(p, "HideWindow"); FreePack(p); } dp->HaltThread = true; Set(dp->Event); WaitThread(t, INFINITE); ReleaseEvent(dp->Event); Free(dp); ReleaseThread(t); Disconnect(s); ReleaseSock(s); return ret; } // Thread for the status indicator client void CncStatusPrinterWindowThreadProc(THREAD *thread, void *param) { CNC_STATUS_PRINTER_WINDOW_PARAM *pp; SOCK *sock; PACK *p; // Validate arguments if (thread == NULL || param == NULL) { return; } pp = (CNC_STATUS_PRINTER_WINDOW_PARAM *)param; sock = pp->Sock; pp->Thread = thread; AddRef(pp->Thread->ref); NoticeThreadInit(thread); p = RecvPack(sock); if (p != NULL) { // Stop the session StopSessionEx(pp->Session, true); FreePack(p); } } // Create a status indicator client SOCK *CncStatusPrinterWindowStart(SESSION *s) { SOCK *sock; PACK *p; THREAD *t; CNC_STATUS_PRINTER_WINDOW_PARAM *param; // Validate arguments if (s == NULL) { return NULL; } sock = CncConnect(); if (sock == NULL) { return NULL; } p = NewPack(); PackAddStr(p, "function", "status_printer"); PackAddUniStr(p, "account_name", s->Account->ClientOption->AccountName); if (SendPack(sock, p) == false) { FreePack(p); ReleaseSock(sock); return NULL; } FreePack(p); param = ZeroMalloc(sizeof(CNC_STATUS_PRINTER_WINDOW_PARAM)); param->Sock = sock; param->Session = s; sock->Param = param; t = NewThread(CncStatusPrinterWindowThreadProc, param); WaitThreadInit(t); ReleaseThread(t); return sock; } // Send a string to the status indicator void CncStatusPrinterWindowPrint(SOCK *s, wchar_t *str) { PACK *p; // Validate arguments if (s == NULL || str == NULL) { return; } p = NewPack(); PackAddUniStr(p, "string", str); SendPack(s, p); FreePack(p); } // Stop the status indicator client void CncStatusPrinterWindowStop(SOCK *s) { CNC_STATUS_PRINTER_WINDOW_PARAM *param; // Validate arguments if (s == NULL) { return; } param = (CNC_STATUS_PRINTER_WINDOW_PARAM *)s->Param; // Disconnect the client socket Disconnect(s); // Terminate the thread WaitThread(param->Thread, INFINITE); ReleaseThread(param->Thread); Free(param); ReleaseSock(s); } // Start the driver installer for Windows Vista bool CncExecDriverInstaller(char *arg) { SOCK *s = CncConnect(); PACK *p; bool ret; if (s == NULL) { return false; } p = NewPack(); PackAddStr(p, "function", "exec_driver_installer"); PackAddStr(p, "arg", arg); SendPack(s, p); FreePack(p); p = RecvPack(s); if (p == NULL) { Disconnect(s); ReleaseSock(s); return false; } ret = PackGetBool(p, "ret"); FreePack(p); Disconnect(s); ReleaseSock(s); return ret; } // Let the current running client notification services releasing the socket void CncReleaseSocket() { SOCK *s = CncConnect(); PACK *p; if (s == NULL) { return; } p = NewPack(); PackAddStr(p, "function", "release_socket"); #ifdef OS_WIN32 PackAddInt(p, "pid", MsGetProcessId()); #endif // OS_WIN32 SendPack(s, p); FreePack(p); Disconnect(s); ReleaseSock(s); } // Terminate the process of the client notification service void CncExit() { SOCK *s = CncConnectEx(256); PACK *p; if (s != NULL) { p = NewPack(); PackAddStr(p, "function", "exit"); SendPack(s, p); FreePack(p); FreePack(RecvPack(s)); Disconnect(s); ReleaseSock(s); } #ifdef OS_WIN32 MsKillOtherInstanceEx("vpnclient"); #endif // OS_WIN32 } // Connect to the client notification service SOCK *CncConnect() { return CncConnectEx(0); } SOCK *CncConnectEx(UINT timeout) { SOCK *s = ConnectEx("localhost", CLIENT_NOTIFY_PORT, timeout); return s; } #ifdef OS_WIN32 // Thread for the certificate check dialog void Win32CnCheckCertThreadProc(THREAD *thread, void *param) { UI_CHECKCERT *dlg; // Validate arguments if (thread == NULL || param == NULL) { return; } dlg = (UI_CHECKCERT *)param; CheckCertDlg(dlg); { PACK *p = NewPack(); PackAddBool(p, "Ok", dlg->Ok); PackAddBool(p, "SaveServerCert", dlg->SaveServerCert); SendPack(dlg->Sock, p); FreePack(p); FreePack(RecvPack(dlg->Sock)); } Disconnect(dlg->Sock); } // Certificate check dialog void Win32CnCheckCert(SOCK *s, PACK *p) { UI_CHECKCERT dlg; THREAD *t; Zero(&dlg, sizeof(dlg)); // Validate arguments if (s == NULL || p == NULL) { return; } PackGetUniStr(p, "AccountName", dlg.AccountName, sizeof(dlg.AccountName)); PackGetStr(p, "ServerName", dlg.ServerName, sizeof(dlg.ServerName)); dlg.x = PackGetX(p, "x"); dlg.parent_x = PackGetX(p, "parent_x"); dlg.old_x = PackGetX(p, "old_x"); dlg.DiffWarning = PackGetBool(p, "DiffWarning"); dlg.Ok = PackGetBool(p, "Ok"); dlg.SaveServerCert = PackGetBool(p, "SaveServerCert"); dlg.Sock = s; t = NewThread(Win32CnCheckCertThreadProc, &dlg); FreePack(RecvPack(s)); dlg.Halt = true; WaitThread(t, INFINITE); ReleaseThread(t); FreeX(dlg.parent_x); FreeX(dlg.old_x); FreeX(dlg.x); } // Message display dialog thread procedure void Win32CnMsgDlgThreadProc(THREAD *thread, void *param) { UI_MSG_DLG *dlg = (UI_MSG_DLG *)param; wchar_t tmp[MAX_SIZE]; char url[MAX_SIZE]; // Validate arguments if (thread == NULL || dlg == NULL) { return; } UniFormat(tmp, sizeof(tmp), _UU("CM_MSG_TITLE"), dlg->ServerName, dlg->HubName); if (IsURLMsg(dlg->Msg, url, sizeof(url)) == false) { OnceMsgEx(NULL, tmp, dlg->Msg, true, 167, &dlg->Halt); } else { if (MsExecute(url, NULL) == false) { OnceMsgEx(NULL, tmp, dlg->Msg, true, 167, &dlg->Halt); } } Disconnect(dlg->Sock); } // NIC information dialog thread procedure void Win32CnNicInfoThreadProc(THREAD *thread, void *param) { UI_NICINFO *info = (UI_NICINFO *)param; // Validate arguments if (thread == NULL || info == NULL) { return; } NicInfo(info); Disconnect(info->Sock); } // NIC information dialog void Win32CnNicInfo(SOCK *s, PACK *p) { UI_NICINFO info; THREAD *t; Zero(&info, sizeof(info)); // Validate arguments if (s == NULL || p == NULL) { return; } PackGetStr(p, "NicName", info.NicName, sizeof(info.NicName)); PackGetUniStr(p, "AccountName", info.AccountName, sizeof(info.AccountName)); info.Sock = s; t = NewThread(Win32CnNicInfoThreadProc, &info); FreePack(RecvPack(s)); info.Halt = true; WaitThread(t, INFINITE); ReleaseThread(t); } // Message display dialog void Win32CnMsgDlg(SOCK *s, PACK *p) { UI_MSG_DLG dlg; THREAD *t; UINT utf_size; char *utf; wchar_t *msg; Zero(&dlg, sizeof(dlg)); // Validate arguments if (s == NULL || p == NULL) { return; } PackGetStr(p, "ServerName", dlg.ServerName, sizeof(dlg.ServerName)); PackGetStr(p, "HubName", dlg.HubName, sizeof(dlg.HubName)); utf_size = PackGetDataSize(p, "Msg"); utf = ZeroMalloc(utf_size + 8); PackGetData(p, "Msg", utf); msg = CopyUtfToUni(utf); Free(utf); dlg.Sock = s; dlg.Msg = msg; t = NewThread(Win32CnMsgDlgThreadProc, &dlg); FreePack(RecvPack(s)); dlg.Halt = true; WaitThread(t, INFINITE); ReleaseThread(t); Free(msg); } // Thread for Password input dialog void Win32CnPasswordDlgThreadProc(THREAD *thread, void *param) { UI_PASSWORD_DLG *dlg; // Validate arguments if (thread == NULL || param == NULL) { return; } dlg = (UI_PASSWORD_DLG *)param; if (PasswordDlg(NULL, dlg)) { PACK *p = NewPack(); PackAddBool(p, "ok", true); PackAddStr(p, "Username", dlg->Username); PackAddStr(p, "Password", dlg->Password); PackAddInt(p, "Type", dlg->Type); PackAddBool(p, "ProxyServer", dlg->ProxyServer); PackAddBool(p, "NoSavePassword", dlg->NoSavePassword); SendPack(dlg->Sock, p); FreePack(p); FreePack(RecvPack(dlg->Sock)); } Disconnect(dlg->Sock); } // Password input dialog void Win32CnPasswordDlg(SOCK *s, PACK *p) { UI_PASSWORD_DLG dlg; THREAD *t = NULL; Zero(&dlg, sizeof(dlg)); // Validate arguments if (s == NULL || p == NULL) { return; } dlg.Type = PackGetInt(p, "Type"); PackGetStr(p, "Username", dlg.Username, sizeof(dlg.Username)); PackGetStr(p, "Password", dlg.Password, sizeof(dlg.Password)); PackGetStr(p, "ServerName", dlg.ServerName, sizeof(dlg.ServerName)); dlg.RetryIntervalSec = PackGetInt(p, "RetryIntervalSec"); dlg.ProxyServer = PackGetBool(p, "ProxyServer"); dlg.AdminMode = PackGetBool(p, "AdminMode"); dlg.ShowNoSavePassword = PackGetBool(p, "ShowNoSavePassword"); dlg.NoSavePassword = PackGetBool(p, "NoSavePassword"); dlg.CancelEvent = NewEvent(); dlg.Sock = s; t = NewThread(Win32CnPasswordDlgThreadProc, &dlg); FreePack(RecvPack(s)); Set(dlg.CancelEvent); WaitThread(t, INFINITE); ReleaseEvent(dlg.CancelEvent); ReleaseThread(t); } // Thread for the connection error dialog void Win32CnConnectErrorDlgThreadProc(THREAD *thread, void *param) { UI_CONNECTERROR_DLG *dlg; // Validate arguments if (thread == NULL || param == NULL) { return; } dlg = (UI_CONNECTERROR_DLG *)param; if (ConnectErrorDlg(dlg)) { PACK *p = NewPack(); PackAddBool(p, "ok", true); PackAddBool(p, "HideWindow", dlg->HideWindow); SendPack(dlg->Sock, p); FreePack(p); FreePack(RecvPack(dlg->Sock)); } Disconnect(dlg->Sock); } // Connection Error dialog (Win32) void Win32CnConnectErrorDlg(SOCK *s, PACK *p) { UI_CONNECTERROR_DLG dlg; THREAD *t; Zero(&dlg, sizeof(dlg)); // Validate arguments if (s == NULL || p == NULL) { return; } PackGetUniStr(p, "AccountName", dlg.AccountName, sizeof(dlg.AccountName)); PackGetStr(p, "ServerName", dlg.ServerName, sizeof(dlg.ServerName)); dlg.Err = PackGetInt(p, "Err"); dlg.CurrentRetryCount = PackGetInt(p, "CurrentRetryCount"); dlg.RetryLimit = PackGetInt(p, "RetryLimit"); dlg.RetryIntervalSec = PackGetInt(p, "RetryIntervalSec"); dlg.HideWindow = PackGetBool(p, "HideWindow"); dlg.CancelEvent = NewEvent(); dlg.Sock = s; t = NewThread(Win32CnConnectErrorDlgThreadProc, &dlg); FreePack(RecvPack(s)); Set(dlg.CancelEvent); WaitThread(t, INFINITE); ReleaseEvent(dlg.CancelEvent); ReleaseThread(t); } // Status indicator (Win32) void Win32CnStatusPrinter(SOCK *s, PACK *p) { STATUS_WINDOW *w; wchar_t account_name[MAX_ACCOUNT_NAME_LEN + 1]; // Validate arguments if (s == NULL || p == NULL) { return; } PackGetUniStr(p, "account_name", account_name, sizeof(account_name)); w = StatusPrinterWindowStart(s, account_name); while (true) { PACK *p = RecvPack(s); if (p == NULL) { // Exit the dialog because it is disconnected break; } else { wchar_t tmp[MAX_SIZE]; // Rewrite the string PackGetUniStr(p, "string", tmp, sizeof(tmp)); StatusPrinterWindowPrint(w, tmp); FreePack(p); } } StatusPrinterWindowStop(w); } // Start the driver installer (for Windows Vista) void Win32CnExecDriverInstaller(SOCK *s, PACK *p) { char arg[MAX_SIZE]; bool ret; void *helper = NULL; // Validate arguments if (s == NULL || p == NULL) { return; } if (PackGetStr(p, "arg", arg, sizeof(arg)) == false) { return; } helper = CmStartUacHelper(); ret = MsExecDriverInstaller(arg); CmStopUacHelper(helper); p = NewPack(); PackAddBool(p, "ret", ret); SendPack(s, p); FreePack(p); } #endif // OS_WIN32 // Start the driver installer void CnExecDriverInstaller(SOCK *s, PACK *p) { // Validate arguments if (s == NULL || p == NULL) { return; } #ifdef OS_WIN32 Win32CnExecDriverInstaller(s, p); #endif // OS_WIN32 } // Certificate confirmation dialog void CnCheckCert(SOCK *s, PACK *p) { // Validate arguments if (s == NULL || p == NULL) { return; } #ifdef OS_WIN32 Win32CnCheckCert(s, p); #endif // OS_WIN32 } // NIC information dialog void CnNicInfo(SOCK *s, PACK *p) { // Validate arguments if (s == NULL || p == NULL) { return; } #ifdef OS_WIN32 Win32CnNicInfo(s, p); #endif // OS_WIN32 } // Message display dialog void CnMsgDlg(SOCK *s, PACK *p) { // Validate arguments if (s == NULL || p == NULL) { return; } #ifdef OS_WIN32 Win32CnMsgDlg(s, p); #endif // OS_WIN32 } // Password input dialog void CnPasswordDlg(SOCK *s, PACK *p) { // Validate arguments if (s == NULL || p == NULL) { return; } #ifdef OS_WIN32 Win32CnPasswordDlg(s, p); #endif // OS_WIN32 } // Connection Error dialog void CnConnectErrorDlg(SOCK *s, PACK *p) { // Validate arguments if (s == NULL || p == NULL) { return; } #ifdef OS_WIN32 Win32CnConnectErrorDlg(s, p); #endif // OS_WIN32 } // Status indicator void CnStatusPrinter(SOCK *s, PACK *p) { // Validate arguments if (s == NULL || p == NULL) { return; } #ifdef OS_WIN32 Win32CnStatusPrinter(s, p); #endif // OS_WIN32 } // Client notification service listener thread void CnListenerProc(THREAD *thread, void *param) { TCP_ACCEPTED_PARAM *data = (TCP_ACCEPTED_PARAM *)param; SOCK *s; PACK *p; // Validate arguments if (data == NULL || thread == NULL) { return; } #ifdef OS_WIN32 //Set Application ID JL_SetCurrentProcessExplicitAppUserModelID(APPID_CM); #endif // OS_WIN32 s = data->s; AddRef(s->ref); NoticeThreadInit(thread); if (IsLocalHostIP(&s->LocalIP)) { p = RecvPack(s); if (p != NULL) { char function[MAX_SIZE]; if (PackGetStr(p, "function", function, sizeof(function))) { if (StrCmpi(function, "status_printer") == 0) { CnStatusPrinter(s, p); } else if (StrCmpi(function, "connecterror_dialog") == 0) { CnConnectErrorDlg(s, p); } else if (StrCmpi(function, "msg_dialog") == 0) { CnMsgDlg(s, p); } else if (StrCmpi(function, "nicinfo") == 0) { CnNicInfo(s, p); } else if (StrCmpi(function, "password_dialog") == 0) { CnPasswordDlg(s, p); } else if (StrCmpi(function, "secure_sign") == 0) { CnSecureSign(s, p); } else if (StrCmpi(function, "check_cert") == 0) { CnCheckCert(s, p); } else if (StrCmpi(function, "exit") == 0) { #ifdef OS_WIN32 MsTerminateProcess(); #else // OS_WIN32 _exit(0); #endif // OS_WIN32 } else if (StrCmpi(function, "get_session_id") == 0) { PACK *p = NewPack(); #ifdef OS_WIN32 PackAddInt(p, "session_id", MsGetCurrentTerminalSessionId()); #endif // OS_WIN32 SendPack(s, p); FreePack(p); } else if (StrCmpi(function, "exec_driver_installer") == 0) { CnExecDriverInstaller(s, p); } else if (StrCmpi(function, "release_socket") == 0) { // Stop the listener CnReleaseSocket(s, p); } } FreePack(p); } } Disconnect(s); ReleaseSock(s); } // Do the Secure Sign void CnSecureSign(SOCK *s, PACK *p) { SECURE_SIGN sign; bool ret = false; // Validate arguments if (s == NULL || p == NULL) { return; } Zero(&sign, sizeof(sign)); InRpcSecureSign(&sign, p); #ifdef OS_WIN32 // Win32: Show dialog ret = Win32CiSecureSign(&sign); #else // OS_WIN32 // UNIX: not implemented ret = false; #endif // OS_WIN32 p = NewPack(); OutRpcSecureSign(p, &sign); FreeRpcSecureSign(&sign); PackAddBool(p, "ret", ret); SendPack(s, p); FreePack(p); } // Stop the listener void CnReleaseSocket(SOCK *s, PACK *p) { UINT pid = 0; UINT current_pid = 0; // Validate arguments if (s == NULL || p == NULL) { return; } pid = PackGetInt(p, "pid"); #ifdef OS_WIN32 current_pid = MsGetProcessId(); #endif // OS_WIN32 if (current_pid == pid) { return; } Lock(cn_listener_lock); { if (cn_listener != NULL) { if (cn_listener->Halt == false) { StopListener(cn_listener); cn_next_allow = Tick64() + (6 * 1000); } } } Unlock(cn_listener_lock); } // Start the client notification service void CnStart() { CEDAR *cedar; LISTENER *o; UINT last_cursor_hash = 0; bool last_session_active = false; cn_next_allow = 0; cn_listener_lock = NewLock(); #ifdef OS_WIN32 MsSetShutdownParameters(0xff, 0x00000001); InitWinUi(_UU("CN_TITLE"), _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE")); #endif // OS_WIN32 cedar = NewCedar(NULL, NULL); if (CnCheckAlreadyExists(true)) { // Already started ReleaseCedar(cedar); #ifdef OS_WIN32 FreeWinUi(); #endif // OS_WIN32 return; } #ifdef OS_WIN32 MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "NotifyServerProcessId", MsGetProcessId()); #endif // OS_WIN32 DisableDosProtect(); BEGIN_LISTENER: Lock(cn_listener_lock); cn_listener = o = NewListenerEx2(cedar, LISTENER_TCP, CLIENT_NOTIFY_PORT, CnListenerProc, NULL, true); Unlock(cn_listener_lock); while (true) { UINT current_cursor_hash = 0; bool cursor_changed = false; #ifdef OS_WIN32 // Get the current cursor position current_cursor_hash = MsGetCursorPosHash(); #endif // OS_WIN32 if (last_cursor_hash != current_cursor_hash) { // Check the cursor position cursor_changed = true; last_cursor_hash = current_cursor_hash; } Lock(cn_listener_lock); // Check the status periodically after that the listener has started if (cn_listener->Status == LISTENER_STATUS_TRYING || cn_listener->Halt) { bool session_active = false; #ifdef OS_WIN32 session_active = MsIsCurrentTerminalSessionActive(); if (cursor_changed) { // If the cursor position is changed but the terminal session is // not active, the cursor position is regarded as not changed. if (session_active == false) { cursor_changed = false; } } if (last_session_active != session_active) { //If the cursor position doesn't changed but the terminal session // became active than previous, the cursor position is regarded as changed. last_session_active = session_active; if (session_active) { cursor_changed = true; } } #endif // OS_WIN32 // If the port cannot be opened if (cn_next_allow <= Tick64()) { #ifdef OS_WIN32 if (cursor_changed) { // It can be judged to have the rights to open the port // since the mouse cursor is moving. // So, take over the port which is owned by other process forcibly CncReleaseSocket(); } #endif // OS_WIN32 if (cn_listener->Halt) { ReleaseListener(cn_listener); cn_listener = NULL; Unlock(cn_listener_lock); goto BEGIN_LISTENER; } } } Unlock(cn_listener_lock); SleepThread(1000); } } // Confirm whether the account file is parsed successfully bool CiTryToParseAccount(BUF *b) { RPC_CLIENT_CREATE_ACCOUNT *a; // Validate arguments if (b == NULL) { return false; } a = CiCfgToAccount(b); if (a != NULL) { CiFreeClientCreateAccount(a); Free(a); return true; } else { return false; } } bool CiTryToParseAccountFile(wchar_t *name) { bool ret; BUF *b; // Validate arguments if (name == NULL) { return false; } b = ReadDumpW(name); if (b == NULL) { return false; } ret = CiTryToParseAccount(b); FreeBuf(b); return ret; } // Confirm whether the account information includes sensitive information bool CiHasAccountSensitiveInformation(BUF *b) { RPC_CLIENT_CREATE_ACCOUNT *a; bool ret = false; // Validate arguments if (b == NULL) { return false; } a = CiCfgToAccount(b); if (a == NULL) { return false; } if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_PASSWORD) { ret = true; } else if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_PLAIN_PASSWORD) { ret = true; } CiFreeClientCreateAccount(a); Free(a); return ret; } // Delete the sensitive information in the account information bool CiEraseSensitiveInAccount(BUF *b) { RPC_CLIENT_CREATE_ACCOUNT *a; BUF *b2; bool ret = false; // Validate arguments if (b == NULL) { return false; } a = CiCfgToAccount(b); if (a == NULL) { return false; } if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_PASSWORD) { Zero(a->ClientAuth->HashedPassword, sizeof(a->ClientAuth->HashedPassword)); ClearStr(a->ClientAuth->Username, sizeof(a->ClientAuth->Username)); } else if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_PLAIN_PASSWORD) { ClearStr(a->ClientAuth->PlainPassword, sizeof(a->ClientAuth->PlainPassword)); ClearStr(a->ClientAuth->Username, sizeof(a->ClientAuth->Username)); } b2 = CiAccountToCfg(a); if (b2 != NULL) { ret = true; ClearBuf(b); WriteBuf(b, b2->Buf, b2->Size); SeekBuf(b, 0, 0); FreeBuf(b2); } CiFreeClientCreateAccount(a); Free(a); return ret; } // Read the account information from the buffer RPC_CLIENT_CREATE_ACCOUNT *CiCfgToAccount(BUF *b) { RPC_CLIENT_CREATE_ACCOUNT *t; FOLDER *f; ACCOUNT *a; // Validate arguments if (b == NULL) { return NULL; } f = CfgBufTextToFolder(b); if (f == NULL) { return NULL; } a = CiLoadClientAccount(f); CfgDeleteFolder(f); if (a == NULL) { return NULL; } DeleteLock(a->lock); t = ZeroMalloc(sizeof(RPC_CLIENT_CREATE_ACCOUNT)); t->ClientOption = a->ClientOption; t->ClientAuth = a->ClientAuth; t->StartupAccount = a->StartupAccount; t->CheckServerCert = a->CheckServerCert; t->RetryOnServerCert = a->RetryOnServerCert; t->AddDefaultCA = a->AddDefaultCA; t->ServerCert = a->ServerCert; Free(a); return t; } // Write the account information to a buffer BUF *CiAccountToCfg(RPC_CLIENT_CREATE_ACCOUNT *t) { BUF *b; FOLDER *root; ACCOUNT a; // Validate arguments if (t == NULL) { return NULL; } root = CfgCreateFolder(NULL, TAG_ROOT); Zero(&a, sizeof(a)); a.ClientOption = t->ClientOption; a.ClientAuth = t->ClientAuth; a.CheckServerCert = t->CheckServerCert; a.RetryOnServerCert = t->RetryOnServerCert; a.AddDefaultCA = t->AddDefaultCA; a.ServerCert = t->ServerCert; a.StartupAccount = t->StartupAccount; CiWriteAccountData(root, &a); b = CfgFolderToBufEx(root, true, true); CfgDeleteFolder(root); return b; } // RPC dispatch routine PACK *CiRpcDispatch(RPC *rpc, char *name, PACK *p) { PACK *ret; CLIENT *c; // Validate arguments if (rpc == NULL || name == NULL || p == NULL) { return NULL; } c = rpc->Param; ret = NewPack(); if (StrCmpi(name, "GetClientVersion") == 0) { RPC_CLIENT_VERSION a; if (CtGetClientVersion(c, &a) == false) { RpcError(ret, c->Err); } else { OutRpcClientVersion(ret, &a); } } else if (StrCmpi(name, "GetCmSetting") == 0) { CM_SETTING a; if (CtGetCmSetting(c, &a) == false) { RpcError(ret, c->Err); } else { OutRpcCmSetting(ret, &a); } } else if (StrCmpi(name, "SetCmSetting") == 0) { CM_SETTING a; Zero(&a, sizeof(a)); InRpcCmSetting(&a, p); if (CtSetCmSetting(c, &a) == false) { RpcError(ret, c->Err); } } else if (StrCmpi(name, "SetPassword") == 0) { RPC_CLIENT_PASSWORD a; InRpcClientPassword(&a, p); if (CtSetPassword(c, &a) == false) { RpcError(ret, c->Err); } } else if (StrCmpi(name, "GetPasswordSetting") == 0) { RPC_CLIENT_PASSWORD_SETTING a; if (CtGetPasswordSetting(c, &a) == false) { RpcError(ret, c->Err); } else { OutRpcClientPasswordSetting(ret, &a); } } else if (StrCmpi(name, "EnumCa") == 0) { RPC_CLIENT_ENUM_CA a; if (CtEnumCa(c, &a) == false) { RpcError(ret, c->Err); } else { OutRpcClientEnumCa(ret, &a); CiFreeClientEnumCa(&a); } } else if (StrCmpi(name, "AddCa") == 0) { RPC_CERT a; InRpcCert(&a, p); if (CtAddCa(c, &a) == false) { RpcError(ret, c->Err); } FreeX(a.x); } else if (StrCmpi(name, "DeleteCa") == 0) { RPC_CLIENT_DELETE_CA a; InRpcClientDeleteCa(&a, p); if (CtDeleteCa(c, &a) == false) { RpcError(ret, c->Err); } } else if (StrCmpi(name, "GetCa") == 0) { RPC_GET_CA a; InRpcGetCa(&a, p); if (CtGetCa(c, &a) == false) { RpcError(ret, c->Err); } else { OutRpcGetCa(ret, &a); } CiFreeGetCa(&a); } else if (StrCmpi(name, "EnumSecure") == 0) { RPC_CLIENT_ENUM_SECURE a; if (CtEnumSecure(c, &a) == false) { RpcError(ret, c->Err); } else { OutRpcClientEnumSecure(ret, &a); CiFreeClientEnumSecure(&a); } } else if (StrCmpi(name, "UseSecure") == 0) { RPC_USE_SECURE a; InRpcUseSecure(&a, p); if (CtUseSecure(c, &a) == false) { RpcError(ret, c->Err); } } else if (StrCmpi(name, "GetUseSecure") == 0) { RPC_USE_SECURE a; Zero(&a, sizeof(a)); if (CtGetUseSecure(c, &a) == false) { RpcError(ret, c->Err); } else { OutRpcUseSecure(ret, &a); } } else if (StrCmpi(name, "EnumObjectInSecure") == 0) { RPC_ENUM_OBJECT_IN_SECURE a; if (CtEnumObjectInSecure(c, &a) == false) { RpcError(ret, c->Err); } else { OutRpcEnumObjectInSecure(ret, &a); CiFreeEnumObjectInSecure(&a); } } else if (StrCmpi(name, "CreateVLan") == 0) { RPC_CLIENT_CREATE_VLAN a; InRpcCreateVLan(&a, p); if (CtCreateVLan(c, &a) == false) { RpcError(ret, c->Err); } } else if (StrCmpi(name, "UpgradeVLan") == 0) { RPC_CLIENT_CREATE_VLAN a; InRpcCreateVLan(&a, p); if (CtUpgradeVLan(c, &a) == false) { RpcError(ret, c->Err); } } else if (StrCmpi(name, "GetVLan") == 0) { RPC_CLIENT_GET_VLAN a; InRpcClientGetVLan(&a, p); if (CtGetVLan(c, &a) == false) { RpcError(ret, c->Err); } else { OutRpcClientGetVLan(ret, &a); } } else if (StrCmpi(name, "SetVLan") == 0) { RPC_CLIENT_SET_VLAN a; InRpcClientSetVLan(&a, p); if (CtSetVLan(c, &a) == false) { RpcError(ret, c->Err); } } else if (StrCmpi(name, "EnumVLan") == 0) { RPC_CLIENT_ENUM_VLAN a; if (CtEnumVLan(c, &a) == false) { RpcError(ret, c->Err); } else { OutRpcClientEnumVLan(ret, &a); CiFreeClientEnumVLan(&a); } } else if (StrCmpi(name, "DeleteVLan") == 0) { RPC_CLIENT_CREATE_VLAN a; InRpcCreateVLan(&a, p); if (CtDeleteVLan(c, &a) == false) { RpcError(ret, c->Err); } } else if (StrCmpi(name, "EnableVLan") == 0) { RPC_CLIENT_CREATE_VLAN a; InRpcCreateVLan(&a, p); if (CtEnableVLan(c, &a) == false) { RpcError(ret, c->Err); } } else if (StrCmpi(name, "DisableVLan") == 0) { RPC_CLIENT_CREATE_VLAN a; InRpcCreateVLan(&a, p); if (CtDisableVLan(c, &a) == false) { RpcError(ret, c->Err); } } else if (StrCmpi(name, "CreateAccount") == 0) { RPC_CLIENT_CREATE_ACCOUNT a; InRpcClientCreateAccount(&a, p); if (CtCreateAccount(c, &a, false) == false) { RpcError(ret, c->Err); } CiFreeClientCreateAccount(&a); } else if (StrCmpi(name, "EnumAccount") == 0) { RPC_CLIENT_ENUM_ACCOUNT a; if (CtEnumAccount(c, &a) == false) { RpcError(ret, c->Err); } else { OutRpcClientEnumAccount(ret, &a); CiFreeClientEnumAccount(&a); } } else if (StrCmpi(name, "DeleteAccount") == 0) { RPC_CLIENT_DELETE_ACCOUNT a; InRpcClientDeleteAccount(&a, p); if (CtDeleteAccount(c, &a, false) == false) { RpcError(ret, c->Err); } } else if (StrCmpi(name, "SetStartupAccount") == 0) { RPC_CLIENT_DELETE_ACCOUNT a; InRpcClientDeleteAccount(&a, p); if (CtSetStartupAccount(c, &a, false) == false) { RpcError(ret, c->Err); } } else if (StrCmpi(name, "RemoveStartupAccount") == 0) { RPC_CLIENT_DELETE_ACCOUNT a; InRpcClientDeleteAccount(&a, p); if (CtRemoveStartupAccount(c, &a) == false) { RpcError(ret, c->Err); } } else if (StrCmpi(name, "GetIssuer") == 0) { RPC_GET_ISSUER a; InRpcGetIssuer(&a, p); if (CtGetIssuer(c, &a)) { OutRpcGetIssuer(ret, &a); } else { RpcError(ret, c->Err); } CiFreeGetIssuer(&a); } else if (StrCmpi(name, "GetCommonProxySetting") == 0) { INTERNET_SETTING t; InRpcInternetSetting(&t, p); if (CtGetCommonProxySetting(c, &t)) { OutRpcInternetSetting(ret, &t); } else { RpcError(ret, c->Err); } } else if (StrCmpi(name, "SetCommonProxySetting") == 0) { INTERNET_SETTING t; InRpcInternetSetting(&t, p); if (CtSetCommonProxySetting(c, &t)) { OutRpcInternetSetting(ret, &t); } else { RpcError(ret, c->Err); } } else if (StrCmpi(name, "SetAccount") == 0) { RPC_CLIENT_CREATE_ACCOUNT a; InRpcClientCreateAccount(&a, p); if (CtSetAccount(c, &a, false) == false) { RpcError(ret, c->Err); } CiFreeClientCreateAccount(&a); } else if (StrCmpi(name, "GetAccount") == 0) { RPC_CLIENT_GET_ACCOUNT a; InRpcClientGetAccount(&a, p); if (CtGetAccount(c, &a) == false) { RpcError(ret, c->Err); } else { OutRpcClientGetAccount(ret, &a); } CiFreeClientGetAccount(&a); } else if (StrCmpi(name, "RenameAccount") == 0) { RPC_RENAME_ACCOUNT a; InRpcRenameAccount(&a, p); if (CtRenameAccount(c, &a, false) == false) { RpcError(ret, c->Err); } } else if (StrCmpi(name, "SetClientConfig") == 0) { CLIENT_CONFIG a; InRpcClientConfig(&a, p); if (CtSetClientConfig(c, &a) == false) { RpcError(ret, c->Err); } } else if (StrCmpi(name, "GetClientConfig") == 0) { CLIENT_CONFIG a; if (CtGetClientConfig(c, &a) == false) { RpcError(ret, c->Err); } else { OutRpcClientConfig(ret, &a); } } else if (StrCmpi(name, "Connect") == 0) { RPC_CLIENT_CONNECT a; InRpcClientConnect(&a, p); if (CtConnect(c, &a) == false) { RpcError(ret, c->Err); } } else if (StrCmpi(name, "Disconnect") == 0) { RPC_CLIENT_CONNECT a; InRpcClientConnect(&a, p); if (CtDisconnect(c, &a, false) == false) { RpcError(ret, c->Err); } } else if (StrCmpi(name, "GetAccountStatus") == 0) { RPC_CLIENT_GET_CONNECTION_STATUS a; InRpcClientGetConnectionStatus(&a, p); if (CtGetAccountStatus(c, &a) == false) { RpcError(ret, c->Err); } else { OutRpcClientGetConnectionStatus(ret, &a); } CiFreeClientGetConnectionStatus(&a); } else { FreePack(ret); ret = NULL; } return ret; } // Set the CM_SETTING UINT CcSetCmSetting(REMOTE_CLIENT *r, CM_SETTING *a) { PACK *ret, *p; UINT err; // Validate arguments if (r == NULL || a == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcCmSetting(p, a); ret = RpcCall(r->Rpc, "SetCmSetting", p); if (RpcIsOk(ret)) { FreePack(ret); return 0; } else { err = RpcGetError(ret); FreePack(ret); return err; } } // Get the CM_SETTING UINT CcGetCmSetting(REMOTE_CLIENT *r, CM_SETTING *a) { PACK *ret; // Validate arguments if (r == NULL || a == NULL) { return ERR_INTERNAL_ERROR; } ret = RpcCall(r->Rpc, "GetCmSetting", NULL); if (RpcIsOk(ret)) { InRpcCmSetting(a, ret); FreePack(ret); return 0; } else { UINT err = RpcGetError(ret); FreePack(ret); return err; } } // Get the client version UINT CcGetClientVersion(REMOTE_CLIENT *r, RPC_CLIENT_VERSION *a) { PACK *ret; // Validate arguments if (r == NULL || a == NULL) { return ERR_INTERNAL_ERROR; } ret = RpcCall(r->Rpc, "GetClientVersion", NULL); if (RpcIsOk(ret)) { InRpcClientVersion(a, ret); FreePack(ret); return 0; } else { UINT err = RpcGetError(ret); FreePack(ret); return err; } } // Set the password UINT CcSetPassword(REMOTE_CLIENT *r, RPC_CLIENT_PASSWORD *pass) { PACK *ret, *p; // Validate arguments if (r == NULL || pass == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcClientPassword(p, pass); ret = RpcCall(r->Rpc, "SetPassword", p); if (RpcIsOk(ret)) { FreePack(ret); return 0; } else { UINT err = RpcGetError(ret); FreePack(ret); return err; } } // Get the password setting UINT CcGetPasswordSetting(REMOTE_CLIENT *r, RPC_CLIENT_PASSWORD_SETTING *a) { PACK *ret; UINT err = 0; // Validate arguments if (r == NULL || a == NULL) { return ERR_INTERNAL_ERROR; } ret = RpcCall(r->Rpc, "GetPasswordSetting", NULL); if (RpcIsOk(ret)) { InRpcClientPasswordSetting(a, ret); } else { err = RpcGetError(ret); } FreePack(ret); return err; } // Enumerate the CA UINT CcEnumCa(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_CA *e) { PACK *ret; UINT err = 0; // Validate arguments if (r == NULL || e == NULL) { return ERR_INTERNAL_ERROR; } ret = RpcCall(r->Rpc, "EnumCa", NULL); if (RpcIsOk(ret)) { InRpcClientEnumCa(e, ret); } else { err = RpcGetError(ret); } FreePack(ret); return err; } // Add the CA UINT CcAddCa(REMOTE_CLIENT *r, RPC_CERT *cert) { PACK *p, *ret; UINT err = 0; // Validate arguments if (r == NULL || cert == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcCert(p, cert); ret = RpcCall(r->Rpc, "AddCa", p); if (RpcIsOk(ret) == false) { err = RpcGetError(ret); } FreePack(ret); return err; } // Delete the CA UINT CcDeleteCa(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_CA *c) { PACK *p, *ret; UINT err = 0; // Validate arguments if (r == NULL || c == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcClientDeleteCa(p, c); ret = RpcCall(r->Rpc, "DeleteCa", p); if (RpcIsOk(ret) == false) { err = RpcGetError(ret); } FreePack(ret); return err; } // Get the issuer UINT CcGetIssuer(REMOTE_CLIENT *r, RPC_GET_ISSUER *a) { PACK *p, *ret; UINT err = 0; // Validate arguments if (r == NULL || a == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcGetIssuer(p, a); ret = RpcCall(r->Rpc, "GetIssuer", p); if (RpcIsOk(ret)) { if (a->x != NULL) { FreeX(a->x); a->x = NULL; } InRpcGetIssuer(a, ret); } else { err = RpcGetError(ret); } FreePack(ret); return err; } // Get the CA UINT CcGetCa(REMOTE_CLIENT *r, RPC_GET_CA *get) { PACK *p, *ret; UINT err = 0; // Validate arguments if (r == NULL || get == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcGetCa(p, get); ret = RpcCall(r->Rpc, "GetCa", p); if (RpcIsOk(ret)) { InRpcGetCa(get, ret); } else { err = RpcGetError(ret); } FreePack(ret); return err; } // Enumeration of the secure devices UINT CcEnumSecure(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_SECURE *e) { PACK *ret; UINT err = 0; // Validate arguments if (r == NULL || e == NULL) { return ERR_INTERNAL_ERROR; } ret = RpcCall(r->Rpc, "EnumSecure", NULL); if (RpcIsOk(ret)) { InRpcClientEnumSecure(e, ret); } else { err = RpcGetError(ret); } FreePack(ret); return err; } // Get the secure device that the user is using UINT CcGetUseSecure(REMOTE_CLIENT *r, RPC_USE_SECURE *sec) { PACK *p, *ret; UINT err = 0; // Validate arguments if (r == NULL || sec == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); ret = RpcCall(r->Rpc, "GetUseSecure", p); if (RpcIsOk(ret) == false) { err = RpcGetError(ret); } else { InRpcUseSecure(sec, ret); } FreePack(ret); return err; } // Use the secure device UINT CcUseSecure(REMOTE_CLIENT *r, RPC_USE_SECURE *sec) { PACK *p, *ret; UINT err = 0; // Validate arguments if (r == NULL || sec == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcUseSecure(p, sec); ret = RpcCall(r->Rpc, "UseSecure", p); if (RpcIsOk(ret) == false) { err = RpcGetError(ret); } FreePack(ret); return err; } // Get a next recommended virtual LAN card name bool CiGetNextRecommendedVLanName(REMOTE_CLIENT *r, char *name, UINT size) { RPC_CLIENT_ENUM_VLAN t; UINT i; bool b; UINT j; bool ok = false; // Validate arguments if (r == NULL || name == NULL) { return false; } Zero(&t, sizeof(t)); if (CcEnumVLan(r, &t) != ERR_NO_ERROR) { return false; } for (i = 1;i < 128;i++) { char tmp[MAX_SIZE]; CiGenerateVLanRegulatedName(tmp, sizeof(tmp), i); b = false; for (j = 0;j < t.NumItem;j++) { if (StrCmpi(t.Items[j]->DeviceName, tmp) == 0) { b = true; break; } } if (b == false) { ok = true; StrCpy(name, size, tmp); break; } } if (ok) { CiFreeClientEnumVLan(&t); } return true; } // Generate a virtual LAN card name automatically void CiGenerateVLanRegulatedName(char *name, UINT size, UINT i) { // Validate arguments if (name == NULL) { return; } if (i == 1) { StrCpy(name, size, "VPN"); } else { Format(name, size, "VPN%u", i); } } // Examine whether the specified name is valid as a virtual LAN card name of Windows 8 and later? bool CiIsValidVLanRegulatedName(char *name) { UINT i; // Validate arguments if (name == NULL) { return false; } for (i = 1;i < 128;i++) { char tmp[MAX_SIZE]; CiGenerateVLanRegulatedName(tmp, sizeof(tmp), i); if (StrCmpi(name, tmp) == 0) { return true; } } return false; } // Create a VLAN UINT CcCreateVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *create) { PACK *ret, *p; UINT err = 0; char *s = NULL; // Validate arguments if (r == NULL || create == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcCreateVLan(p, create); #ifdef OS_WIN32 s = MsNoWarningSoundInit(); #endif // OS_WIN32 ret = RpcCall(r->Rpc, "CreateVLan", p); #ifdef OS_WIN32 MsNoWarningSoundFree(s); #endif // OS_WIN32 if (RpcIsOk(ret) == false) { err = RpcGetError(ret); } FreePack(ret); return err; } // Upgrade the VLAN UINT CcUpgradeVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *create) { PACK *ret, *p; UINT err = 0; char *s = NULL; // Validate arguments if (r == NULL || create == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcCreateVLan(p, create); #ifdef OS_WIN32 s = MsNoWarningSoundInit(); #endif // OS_WIN32 ret = RpcCall(r->Rpc, "UpgradeVLan", p); #ifdef OS_WIN32 MsNoWarningSoundFree(s); #endif // OS_WIN32 if (RpcIsOk(ret) == false) { err = RpcGetError(ret); } FreePack(ret); return err; } // Get the VLAN UINT CcGetVLan(REMOTE_CLIENT *r, RPC_CLIENT_GET_VLAN *get) { PACK *ret, *p; UINT err = 0; // Validate arguments if (r == NULL || get == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcClientGetVLan(p, get); ret = RpcCall(r->Rpc, "GetVLan", p); if (RpcIsOk(ret)) { InRpcClientGetVLan(get, ret); } else { err = RpcGetError(ret); } FreePack(ret); return err; } // VLAN configuration UINT CcSetVLan(REMOTE_CLIENT *r, RPC_CLIENT_SET_VLAN *set) { PACK *ret, *p; UINT err = 0; // Validate arguments if (r == NULL || set == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcClientSetVLan(p, set); ret = RpcCall(r->Rpc, "SetVLan", p); if (RpcIsOk(ret) == false) { err = RpcGetError(ret); } FreePack(ret); return err; } // Enumeration of VLAN UINT CcEnumVLan(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_VLAN *e) { PACK *ret; UINT err = 0; // Validate arguments if (r == NULL || e == NULL) { return ERR_INTERNAL_ERROR; } ret = RpcCall(r->Rpc, "EnumVLan", NULL); if (RpcIsOk(ret)) { InRpcClientEnumVLan(e, ret); } else { err = RpcGetError(ret); } FreePack(ret); return err; } // Delete the VLAN UINT CcDeleteVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *d) { PACK *ret, *p; UINT err = 0; // Validate arguments if (r == NULL || d == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcCreateVLan(p, d); ret = RpcCall(r->Rpc, "DeleteVLan", p); if (RpcIsOk(ret) == false) { err = RpcGetError(ret); } FreePack(ret); return err; } // Enable the VLAN UINT CcEnableVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *vlan) { PACK *ret, *p; UINT err = 0; // Validate arguments if (r == NULL || vlan == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcCreateVLan(p, vlan); ret = RpcCall(r->Rpc, "EnableVLan", p); if (RpcIsOk(ret) == false) { err = RpcGetError(ret); } FreePack(ret); return err; } // Disable the VLAN UINT CcDisableVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *vlan) { PACK *ret, *p; UINT err = 0; // Validate arguments if (r == NULL || vlan == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcCreateVLan(p, vlan); ret = RpcCall(r->Rpc, "DisableVLan", p); if (RpcIsOk(ret) == false) { err = RpcGetError(ret); } FreePack(ret); return err; } // Create an Account UINT CcCreateAccount(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_ACCOUNT *a) { PACK *ret, *p; UINT err = 0; // Validate arguments if (r == NULL || a == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcClientCreateAccount(p, a); ret = RpcCall(r->Rpc, "CreateAccount", p); if (RpcIsOk(ret) == false) { err = RpcGetError(ret); } FreePack(ret); return err; } // Enumeration of accounts UINT CcEnumAccount(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_ACCOUNT *e) { PACK *ret; UINT err = 0; // Validate arguments if (r == NULL || e == NULL) { return ERR_INTERNAL_ERROR; } ret = RpcCall(r->Rpc, "EnumAccount", NULL); if (RpcIsOk(ret)) { UINT i; InRpcClientEnumAccount(e, ret); for (i = 0;i < e->NumItem;i++) { RPC_CLIENT_ENUM_ACCOUNT_ITEM *t = e->Items[i]; if (IsEmptyStr(t->HubName) && t->Port == 0) { UINT err2; RPC_CLIENT_GET_ACCOUNT a; // Because the Client Manager can not get the port number and HUB name // when enumerating in the VPN Client of the old version, get these separately. Zero(&a, sizeof(a)); UniStrCpy(a.AccountName, sizeof(a.AccountName), t->AccountName); err2 = CcGetAccount(r, &a); if (err2 == ERR_NO_ERROR) { StrCpy(t->HubName, sizeof(t->HubName), a.ClientOption->HubName); t->Port = a.ClientOption->Port; CiFreeClientGetAccount(&a); } } } } else { err = RpcGetError(ret); } FreePack(ret); return err; } // Unset the startup flag of the account UINT CcRemoveStartupAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a) { PACK *ret, *p; UINT err = 0; // Validate arguments if (r == NULL || a == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcClientDeleteAccount(p, a); ret = RpcCall(r->Rpc, "RemoveStartupAccount", p); if (RpcIsOk(ret) == false) { err = RpcGetError(ret); } FreePack(ret); return err; } // Set to start-up flag of the account UINT CcSetStartupAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a) { PACK *ret, *p; UINT err = 0; // Validate arguments if (r == NULL || a == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcClientDeleteAccount(p, a); ret = RpcCall(r->Rpc, "SetStartupAccount", p); if (RpcIsOk(ret) == false) { err = RpcGetError(ret); } FreePack(ret); return err; } // Delete the account UINT CcDeleteAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a) { PACK *ret, *p; UINT err = 0; // Validate arguments if (r == NULL || a == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcClientDeleteAccount(p, a); ret = RpcCall(r->Rpc, "DeleteAccount", p); if (RpcIsOk(ret) == false) { err = RpcGetError(ret); } FreePack(ret); return err; } // Account setting UINT CcSetAccount(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_ACCOUNT *a) { PACK *ret, *p; UINT err = 0; // Validate arguments if (r == NULL || a == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcClientCreateAccount(p, a); ret = RpcCall(r->Rpc, "SetAccount", p); if (RpcIsOk(ret) == false) { err = RpcGetError(ret); } FreePack(ret); return err; } // Get the account UINT CcGetAccount(REMOTE_CLIENT *r, RPC_CLIENT_GET_ACCOUNT *a) { PACK *ret, *p; UINT err = 0; // Validate arguments if (r == NULL || a == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcClientGetAccount(p, a); ret = RpcCall(r->Rpc, "GetAccount", p); if (RpcIsOk(ret)) { InRpcClientGetAccount(a, ret); } else { err = RpcGetError(ret); } FreePack(ret); return err; } // Change the account name UINT CcRenameAccount(REMOTE_CLIENT *r, RPC_RENAME_ACCOUNT *rename) { PACK *p, *ret; UINT err = 0; // Validate arguments if (r == NULL || rename == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcRenameAccount(p, rename); ret = RpcCall(r->Rpc, "RenameAccount", p); if (RpcIsOk(ret) == false) { err = RpcGetError(ret); } FreePack(ret); return err; } // Set the Client configuration UINT CcSetClientConfig(REMOTE_CLIENT *r, CLIENT_CONFIG *o) { PACK *p, *ret; UINT err = 0; // Validate arguments if (r == NULL || o == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcClientConfig(p, o); ret = RpcCall(r->Rpc, "SetClientConfig", p); if (RpcIsOk(ret) == false) { err = RpcGetError(ret); } FreePack(ret); return err; } // Get the client configuration UINT CcGetClientConfig(REMOTE_CLIENT *r, CLIENT_CONFIG *o) { PACK *ret; UINT err = 0; // Validate arguments if (r == NULL || o == NULL) { return ERR_INTERNAL_ERROR; } ret = RpcCall(r->Rpc, "GetClientConfig", NULL); if (RpcIsOk(ret)) { InRpcClientConfig(o, ret); } else { err = RpcGetError(ret); } FreePack(ret); return err; } // Set the service to foreground process void CcSetServiceToForegroundProcess(REMOTE_CLIENT *r) { // Validate arguments if (r == NULL) { return; } // Abolition /* if (r->Rpc != NULL && r->Rpc->Sock != NULL && r->Rpc->Sock->RemoteIP.addr[0] == 127) { if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) && GET_KETA(GetOsInfo()->OsType, 100) >= 2) { // Only on a Windows 2000 or later RPC_CLIENT_VERSION v; Zero(&v, sizeof(v)); if (r->ClientBuildInt == 0) { CcGetClientVersion(r, &v); r->ClientBuildInt = v.ClientBuildInt; r->ProcessId = v.ProcessId; } if (r->ProcessId != 0 && r->ClientBuildInt <= 5080) { #ifdef OS_WIN32 // Set the service process as a foreground window AllowFGWindow(v.ProcessId); #endif // OS_WIN32 } } }*/ } // Connect UINT CcConnect(REMOTE_CLIENT *r, RPC_CLIENT_CONNECT *connect) { PACK *ret, *p; UINT err = 0; // Validate arguments if (r == NULL || connect == NULL) { return ERR_INTERNAL_ERROR; } CcSetServiceToForegroundProcess(r); p = NewPack(); OutRpcClientConnect(p, connect); ret = RpcCall(r->Rpc, "Connect", p); if (RpcIsOk(ret) == false) { err = RpcGetError(ret); } FreePack(ret); return err; } // Disconnect UINT CcDisconnect(REMOTE_CLIENT *r, RPC_CLIENT_CONNECT *connect) { PACK *ret, *p; UINT err = 0; // Validate arguments if (r == NULL || connect == NULL) { return ERR_INTERNAL_ERROR; } CcSetServiceToForegroundProcess(r); p = NewPack(); OutRpcClientConnect(p, connect); ret = RpcCall(r->Rpc, "Disconnect", p); if (RpcIsOk(ret) == false) { err = RpcGetError(ret); } FreePack(ret); return err; } // Get the account status UINT CcGetAccountStatus(REMOTE_CLIENT *r, RPC_CLIENT_GET_CONNECTION_STATUS *st) { PACK *ret, *p; UINT err = 0; // Validate arguments if (r == NULL || st == NULL) { return ERR_INTERNAL_ERROR; } p = NewPack(); OutRpcClientGetConnectionStatus(p, st); ret = RpcCall(r->Rpc, "GetAccountStatus", p); if (RpcIsOk(ret)) { InRpcClientGetConnectionStatus(st, ret); } else { err = RpcGetError(ret); } FreePack(ret); return err; } // Client service sends a notification to the connection manager void CiNotify(CLIENT *c) { CiNotifyInternal(c); } void CiNotifyInternal(CLIENT *c) { // Validate arguments if (c == NULL) { return; } // Set all the notification event LockList(c->NotifyCancelList); { UINT i; for (i = 0;i < LIST_NUM(c->NotifyCancelList);i++) { CANCEL *cancel = LIST_DATA(c->NotifyCancelList, i); Cancel(cancel); } } UnlockList(c->NotifyCancelList); } // Release the RPC_CLIENT_ENUM_ACCOUNT void CiFreeClientEnumAccount(RPC_CLIENT_ENUM_ACCOUNT *a) { UINT i; // Validate arguments if (a == NULL) { return; } for (i = 0;i < a->NumItem;i++) { RPC_CLIENT_ENUM_ACCOUNT_ITEM *e = a->Items[i]; Free(e); } Free(a->Items); } // Thread to save the configuration file periodically void CiSaverThread(THREAD *t, void *param) { CLIENT *c = (CLIENT *)param; // Validate arguments if (t == NULL || param == NULL) { return; } NoticeThreadInit(t); // Wait for a certain period of time while (c->Halt == false) { Wait(c->SaverHalter, CLIENT_SAVER_INTERVAL); // Save CiSaveConfigurationFile(c); } } // Initialize the Saver void CiInitSaver(CLIENT *c) { // Validate arguments if (c == NULL) { return; } c->SaverHalter = NewEvent(); c->SaverThread = NewThread(CiSaverThread, c); WaitThreadInit(c->SaverThread); } // Release the Saver void CiFreeSaver(CLIENT *c) { // Validate arguments if (c == NULL) { return; } c->Halt = true; Set(c->SaverHalter); WaitThread(c->SaverThread, INFINITE); ReleaseThread(c->SaverThread); ReleaseEvent(c->SaverHalter); } // CM_SETTING void InRpcCmSetting(CM_SETTING *c, PACK *p) { // Validate arguments if (c == NULL || p == NULL) { return; } Zero(c, sizeof(CM_SETTING)); c->EasyMode = PackGetBool(p, "EasyMode"); c->LockMode = PackGetBool(p, "LockMode"); PackGetData2(p, "HashedPassword", c->HashedPassword, sizeof(c->HashedPassword)); } void OutRpcCmSetting(PACK *p, CM_SETTING *c) { // Validate arguments if (c == NULL || p == NULL) { return; } PackAddBool(p, "EasyMode", c->EasyMode); PackAddBool(p, "LockMode", c->LockMode); PackAddData(p, "HashedPassword", c->HashedPassword, sizeof(c->HashedPassword)); } // CLIENT_CONFIG void InRpcClientConfig(CLIENT_CONFIG *c, PACK *p) { // Validate arguments if (c == NULL || p == NULL) { return; } Zero(c, sizeof(CLIENT_CONFIG)); c->UseKeepConnect = PackGetInt(p, "UseKeepConnect") == 0 ? false : true; c->KeepConnectPort = PackGetInt(p, "KeepConnectPort"); c->KeepConnectProtocol = PackGetInt(p, "KeepConnectProtocol"); c->KeepConnectInterval = PackGetInt(p, "KeepConnectInterval"); c->AllowRemoteConfig = PackGetInt(p, "AllowRemoteConfig") == 0 ? false : true; PackGetStr(p, "KeepConnectHost", c->KeepConnectHost, sizeof(c->KeepConnectHost)); } void OutRpcClientConfig(PACK *p, CLIENT_CONFIG *c) { // Validate arguments if (c == NULL || p == NULL) { return; } PackAddInt(p, "UseKeepConnect", c->UseKeepConnect); PackAddInt(p, "KeepConnectPort", c->KeepConnectPort); PackAddInt(p, "KeepConnectProtocol", c->KeepConnectProtocol); PackAddInt(p, "KeepConnectInterval", c->KeepConnectInterval); PackAddInt(p, "AllowRemoteConfig", c->AllowRemoteConfig); PackAddStr(p, "KeepConnectHost", c->KeepConnectHost); } // RPC_CLIENT_VERSION void InRpcClientVersion(RPC_CLIENT_VERSION *ver, PACK *p) { // Validate arguments if (ver == NULL || p == NULL) { return; } Zero(ver, sizeof(RPC_CLIENT_VERSION)); PackGetStr(p, "ClientProductName", ver->ClientProductName, sizeof(ver->ClientProductName)); PackGetStr(p, "ClientVersionString", ver->ClientVersionString, sizeof(ver->ClientVersionString)); PackGetStr(p, "ClientBuildInfoString", ver->ClientBuildInfoString, sizeof(ver->ClientBuildInfoString)); ver->ClientVerInt = PackGetInt(p, "ClientVerInt"); ver->ClientBuildInt = PackGetInt(p, "ClientBuildInt"); ver->ProcessId = PackGetInt(p, "ProcessId"); ver->OsType = PackGetInt(p, "OsType"); ver->IsVLanNameRegulated = PackGetBool(p, "IsVLanNameRegulated"); ver->IsVgcSupported = PackGetBool(p, "IsVgcSupported"); ver->ShowVgcLink = PackGetBool(p, "ShowVgcLink"); PackGetStr(p, "ClientId", ver->ClientId, sizeof(ver->ClientId)); } void OutRpcClientVersion(PACK *p, RPC_CLIENT_VERSION *ver) { // Validate arguments if (ver == NULL || p == NULL) { return; } PackAddStr(p, "ClientProductName", ver->ClientProductName); PackAddStr(p, "ClientVersionString", ver->ClientVersionString); PackAddStr(p, "ClientBuildInfoString", ver->ClientBuildInfoString); PackAddInt(p, "ClientVerInt", ver->ClientVerInt); PackAddInt(p, "ClientBuildInt", ver->ClientBuildInt); PackAddInt(p, "ProcessId", ver->ProcessId); PackAddInt(p, "OsType", ver->OsType); PackAddBool(p, "IsVLanNameRegulated", ver->IsVLanNameRegulated); PackAddBool(p, "IsVgcSupported", ver->IsVgcSupported); PackAddBool(p, "ShowVgcLink", ver->ShowVgcLink); PackAddStr(p, "ClientId", ver->ClientId); } // RPC_CLIENT_PASSWORD void InRpcClientPassword(RPC_CLIENT_PASSWORD *pw, PACK *p) { // Validate arguments if (pw == NULL || p == NULL) { return; } Zero(pw, sizeof(RPC_CLIENT_PASSWORD)); PackGetStr(p, "Password", pw->Password, sizeof(pw->Password)); pw->PasswordRemoteOnly = PackGetInt(p, "PasswordRemoteOnly"); } void OutRpcClientPassword(PACK *p, RPC_CLIENT_PASSWORD *pw) { // Validate arguments if (pw == NULL || p == NULL) { return; } PackAddStr(p, "Password", pw->Password); PackAddInt(p, "PasswordRemoteOnly", pw->PasswordRemoteOnly); } // RPC_CLIENT_PASSWORD_SETTING void InRpcClientPasswordSetting(RPC_CLIENT_PASSWORD_SETTING *a, PACK *p) { // Validate arguments if (a == NULL || p == NULL) { return; } Zero(a, sizeof(RPC_CLIENT_PASSWORD_SETTING)); a->IsPasswordPresented = PackGetInt(p, "IsPasswordPresented") == 0 ? false : true; a->PasswordRemoteOnly = PackGetInt(p, "PasswordRemoteOnly") == 0 ? false : true; } void OutRpcClientPasswordSetting(PACK *p, RPC_CLIENT_PASSWORD_SETTING *a) { // Validate arguments if (a == NULL || p == NULL) { return; } PackAddInt(p, "IsPasswordPresented", a->IsPasswordPresented); PackAddInt(p, "PasswordRemoteOnly", a->PasswordRemoteOnly); } // RPC_CLIENT_ENUM_CA void InRpcClientEnumCa(RPC_CLIENT_ENUM_CA *e, PACK *p) { UINT i; // Validate arguments if (e == NULL || p == NULL) { return; } Zero(e, sizeof(RPC_CLIENT_ENUM_CA)); e->NumItem = PackGetNum(p, "NumItem"); e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_CA_ITEM *) * e->NumItem); for (i = 0;i < e->NumItem;i++) { RPC_CLIENT_ENUM_CA_ITEM *item = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_CA_ITEM)); e->Items[i] = item; item->Key = PackGetIntEx(p, "Key", i); PackGetUniStrEx(p, "SubjectName", item->SubjectName, sizeof(item->SubjectName), i); PackGetUniStrEx(p, "IssuerName", item->IssuerName, sizeof(item->IssuerName), i); item->Expires = PackGetInt64Ex(p, "Expires", i); } } void OutRpcClientEnumCa(PACK *p, RPC_CLIENT_ENUM_CA *e) { UINT i; // Validate arguments if (e == NULL || p == NULL) { return; } PackAddNum(p, "NumItem", e->NumItem); PackSetCurrentJsonGroupName(p, "CAList"); for (i = 0;i < e->NumItem;i++) { RPC_CLIENT_ENUM_CA_ITEM *item = e->Items[i]; PackAddIntEx(p, "Key", item->Key, i, e->NumItem); PackAddUniStrEx(p, "SubjectName", item->SubjectName, i, e->NumItem); PackAddUniStrEx(p, "IssuerName", item->IssuerName, i, e->NumItem); PackAddTime64Ex(p, "Expires", item->Expires, i, e->NumItem); } PackSetCurrentJsonGroupName(p, NULL); } // RPC_GET_ISSUER void InRpcGetIssuer(RPC_GET_ISSUER *c, PACK *p) { BUF *b; // Validate arguments if (c == NULL || p == NULL) { return; } Zero(c, sizeof(RPC_GET_ISSUER)); b = PackGetBuf(p, "x"); if (b != NULL) { if (c->x != NULL) { FreeX(c->x); } c->x = BufToX(b, false); FreeBuf(b); } b = PackGetBuf(p, "issuer_x"); if (b != NULL) { c->issuer_x = BufToX(b, false); FreeBuf(b); } } void OutRpcGetIssuer(PACK *p, RPC_GET_ISSUER *c) { BUF *b; // Validate arguments if (p == NULL || c == NULL) { return; } if (c->x != NULL) { b = XToBuf(c->x, false); PackAddBuf(p, "x", b); FreeBuf(b); } if (c->issuer_x != NULL) { b = XToBuf(c->issuer_x, false); PackAddBuf(p, "issuer_x", b); FreeBuf(b); } } // TRAFFIC_EX void InRpcTrafficEx(TRAFFIC *t, PACK *p, UINT i) { // Validate arguments if (t == NULL || p == NULL) { return; } Zero(t, sizeof(TRAFFIC)); t->Recv.BroadcastBytes = PackGetInt64Ex(p, "Ex.Recv.BroadcastBytes", i); t->Recv.BroadcastCount = PackGetInt64Ex(p, "Ex.Recv.BroadcastCount", i); t->Recv.UnicastBytes = PackGetInt64Ex(p, "Ex.Recv.UnicastBytes", i); t->Recv.UnicastCount = PackGetInt64Ex(p, "Ex.Recv.UnicastCount", i); t->Send.BroadcastBytes = PackGetInt64Ex(p, "Ex.Send.BroadcastBytes", i); t->Send.BroadcastCount = PackGetInt64Ex(p, "Ex.Send.BroadcastCount", i); t->Send.UnicastBytes = PackGetInt64Ex(p, "Ex.Send.UnicastBytes", i); t->Send.UnicastCount = PackGetInt64Ex(p, "Ex.Send.UnicastCount", i); } void OutRpcTrafficEx(TRAFFIC *t, PACK *p, UINT i, UINT num) { // Validate arguments if (t == NULL || p == NULL) { return; } PackAddInt64Ex(p, "Ex.Recv.BroadcastBytes", t->Recv.BroadcastBytes, i, num); PackAddInt64Ex(p, "Ex.Recv.BroadcastCount", t->Recv.BroadcastCount, i, num); PackAddInt64Ex(p, "Ex.Recv.UnicastBytes", t->Recv.UnicastBytes, i, num); PackAddInt64Ex(p, "Ex.Recv.UnicastCount", t->Recv.UnicastCount, i, num); PackAddInt64Ex(p, "Ex.Send.BroadcastBytes", t->Send.BroadcastBytes, i, num); PackAddInt64Ex(p, "Ex.Send.BroadcastCount", t->Send.BroadcastCount, i, num); PackAddInt64Ex(p, "Ex.Send.UnicastBytes", t->Send.UnicastBytes, i, num); PackAddInt64Ex(p, "Ex.Send.UnicastCount", t->Send.UnicastCount, i, num); } // TRAFFIC void InRpcTraffic(TRAFFIC *t, PACK *p) { // Validate arguments if (t == NULL || p == NULL) { return; } Zero(t, sizeof(TRAFFIC)); t->Recv.BroadcastBytes = PackGetInt64(p, "Recv.BroadcastBytes"); t->Recv.BroadcastCount = PackGetInt64(p, "Recv.BroadcastCount"); t->Recv.UnicastBytes = PackGetInt64(p, "Recv.UnicastBytes"); t->Recv.UnicastCount = PackGetInt64(p, "Recv.UnicastCount"); t->Send.BroadcastBytes = PackGetInt64(p, "Send.BroadcastBytes"); t->Send.BroadcastCount = PackGetInt64(p, "Send.BroadcastCount"); t->Send.UnicastBytes = PackGetInt64(p, "Send.UnicastBytes"); t->Send.UnicastCount = PackGetInt64(p, "Send.UnicastCount"); } void OutRpcTraffic(PACK *p, TRAFFIC *t) { // Validate arguments if (t == NULL || p == NULL) { return; } PackAddInt64(p, "Recv.BroadcastBytes", t->Recv.BroadcastBytes); PackAddInt64(p, "Recv.BroadcastCount", t->Recv.BroadcastCount); PackAddInt64(p, "Recv.UnicastBytes", t->Recv.UnicastBytes); PackAddInt64(p, "Recv.UnicastCount", t->Recv.UnicastCount); PackAddInt64(p, "Send.BroadcastBytes", t->Send.BroadcastBytes); PackAddInt64(p, "Send.BroadcastCount", t->Send.BroadcastCount); PackAddInt64(p, "Send.UnicastBytes", t->Send.UnicastBytes); PackAddInt64(p, "Send.UnicastCount", t->Send.UnicastCount); } // RPC_CERT void InRpcCert(RPC_CERT *c, PACK *p) { BUF *b; // Validate arguments if (c == NULL || p == NULL) { return; } Zero(c, sizeof(RPC_CERT)); b = PackGetBuf(p, "x"); if (b == NULL) { return; } c->x = BufToX(b, false); FreeBuf(b); } void OutRpcCert(PACK *p, RPC_CERT *c) { BUF *b; // Validate arguments if (p == NULL || c == NULL) { return; } if (c->x != NULL) { b = XToBuf(c->x, false); PackAddBuf(p, "x", b); FreeBuf(b); } } // RPC_CLIENT_DELETE_CA void InRpcClientDeleteCa(RPC_CLIENT_DELETE_CA *c, PACK *p) { // Validate arguments if (c == NULL || p == NULL) { return; } Zero(c, sizeof(RPC_CLIENT_DELETE_CA)); c->Key = PackGetInt(p, "Key"); } void OutRpcClientDeleteCa(PACK *p, RPC_CLIENT_DELETE_CA *c) { // Validate arguments if (c == NULL || p == NULL) { return; } PackAddInt(p, "Key", c->Key); } // RPC_GET_CA void InRpcGetCa(RPC_GET_CA *c, PACK *p) { BUF *b; // Validate arguments if (c == NULL || p == NULL) { return; } Zero(c, sizeof(RPC_GET_CA)); c->Key = PackGetInt(p, "Key"); b = PackGetBuf(p, "x"); if (b != NULL) { c->x = BufToX(b, false); FreeBuf(b); } } void OutRpcGetCa(PACK *p, RPC_GET_CA *c) { // Validate arguments if (c == NULL || p == NULL) { return; } PackAddInt(p, "Key", c->Key); if (c->x != NULL) { BUF *b = XToBuf(c->x, false); PackAddBuf(p, "x", b); FreeBuf(b); } } // RPC_CLIENT_ENUM_SECURE void InRpcClientEnumSecure(RPC_CLIENT_ENUM_SECURE *e, PACK *p) { UINT i; // Validate arguments if (e == NULL || p == NULL) { return; } Zero(e, sizeof(RPC_CLIENT_ENUM_SECURE)); e->NumItem = PackGetNum(p, "NumItem"); e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_SECURE_ITEM *) * e->NumItem); for (i = 0;i < e->NumItem;i++) { RPC_CLIENT_ENUM_SECURE_ITEM *item = e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_SECURE_ITEM)); item->DeviceId = PackGetIntEx(p, "DeviceId", i); item->Type = PackGetIntEx(p, "Type", i); PackGetStrEx(p, "DeviceName", item->DeviceName, sizeof(item->DeviceName), i); PackGetStrEx(p, "Manufacturer", item->Manufacturer, sizeof(item->Manufacturer), i); } } void OutRpcClientEnumSecure(PACK *p, RPC_CLIENT_ENUM_SECURE *e) { UINT i; // Validate arguments if (e == NULL || p == NULL) { return; } PackAddNum(p, "NumItem", e->NumItem); PackSetCurrentJsonGroupName(p, "SecureDeviceList"); for (i = 0;i < e->NumItem;i++) { RPC_CLIENT_ENUM_SECURE_ITEM *item = e->Items[i]; PackAddIntEx(p, "DeviceId", item->DeviceId, i, e->NumItem); PackAddIntEx(p, "Type", item->Type, i, e->NumItem); PackAddStrEx(p, "DeviceName", item->DeviceName, i, e->NumItem); PackAddStrEx(p, "Manufacturer", item->Manufacturer, i, e->NumItem); } PackSetCurrentJsonGroupName(p, NULL); } // RPC_USE_SECURE void InRpcUseSecure(RPC_USE_SECURE *u, PACK *p) { // Validate arguments if (u == NULL || p == NULL) { return; } Zero(u, sizeof(RPC_USE_SECURE)); u->DeviceId = PackGetInt(p, "DeviceId"); } void OutRpcUseSecure(PACK *p, RPC_USE_SECURE *u) { // Validate arguments if (u == NULL || p == NULL) { return; } PackAddInt(p, "DeviceId", u->DeviceId); } // Release the RPC_ENUM_OBJECT_IN_SECURE void CiFreeEnumObjectInSecure(RPC_ENUM_OBJECT_IN_SECURE *a) { UINT i; // Validate arguments if (a == NULL) { return; } for (i = 0;i < a->NumItem;i++) { Free(a->ItemName[i]); } Free(a->ItemName); Free(a->ItemType); } // RPC_ENUM_OBJECT_IN_SECURE void OutRpcEnumObjectInSecure(PACK *p, RPC_ENUM_OBJECT_IN_SECURE *e) { UINT i; // Validate arguments if (e == NULL || p == NULL) { return; } PackAddNum(p, "NumItem", e->NumItem); PackAddInt(p, "hWnd", e->hWnd); PackSetCurrentJsonGroupName(p, "ObjectList"); for (i = 0;i < e->NumItem;i++) { PackAddStrEx(p, "ItemName", e->ItemName[i], i, e->NumItem); PackAddIntEx(p, "ItemType", e->ItemType[i], i, e->NumItem); } PackSetCurrentJsonGroupName(p, NULL); } // RPC_CLIENT_CREATE_VLAN void InRpcCreateVLan(RPC_CLIENT_CREATE_VLAN *v, PACK *p) { // Validate arguments if (v == NULL || p == NULL) { return; } Zero(v, sizeof(RPC_CLIENT_CREATE_VLAN)); PackGetStr(p, "DeviceName", v->DeviceName, sizeof(v->DeviceName)); } void OutRpcCreateVLan(PACK *p, RPC_CLIENT_CREATE_VLAN *v) { // Validate arguments if (v == NULL || p == NULL) { return; } PackAddStr(p, "DeviceName", v->DeviceName); } // RPC_CLIENT_GET_VLAN void InRpcClientGetVLan(RPC_CLIENT_GET_VLAN *v, PACK *p) { // Validate arguments if (v == NULL || p == NULL) { return; } Zero(v, sizeof(RPC_CLIENT_GET_VLAN)); PackGetStr(p, "DeviceName", v->DeviceName, sizeof(v->DeviceName)); v->Enabled = PackGetInt(p, "Enabled") ? true : false; PackGetStr(p, "MacAddress", v->MacAddress, sizeof(v->MacAddress)); PackGetStr(p, "Version", v->Version, sizeof(v->Version)); PackGetStr(p, "FileName", v->FileName, sizeof(v->FileName)); PackGetStr(p, "Guid", v->Guid, sizeof(v->Guid)); } void OutRpcClientGetVLan(PACK *p, RPC_CLIENT_GET_VLAN *v) { // Validate arguments if (v == NULL || p == NULL) { return; } PackAddStr(p, "DeviceName", v->DeviceName); PackAddInt(p, "Enabled", v->Enabled); PackAddStr(p, "MacAddress", v->MacAddress); PackAddStr(p, "Version", v->Version); PackAddStr(p, "FileName", v->FileName); PackAddStr(p, "Guid", v->Guid); } // RPC_CLIENT_SET_VLAN void InRpcClientSetVLan(RPC_CLIENT_SET_VLAN *v, PACK *p) { // Validate arguments if (v == NULL || p == NULL) { return; } Zero(v, sizeof(RPC_CLIENT_SET_VLAN)); PackGetStr(p, "DeviceName", v->DeviceName, sizeof(v->DeviceName)); PackGetStr(p, "MacAddress", v->MacAddress, sizeof(v->MacAddress)); } void OutRpcClientSetVLan(PACK *p, RPC_CLIENT_SET_VLAN *v) { // Validate arguments if (v == NULL || p == NULL) { return; } PackAddStr(p, "DeviceName", v->DeviceName); PackAddStr(p, "MacAddress", v->MacAddress); } // RPC_CLIENT_ENUM_VLAN void InRpcClientEnumVLan(RPC_CLIENT_ENUM_VLAN *v, PACK *p) { UINT i; // Validate arguments if (v == NULL || p == NULL) { return; } Zero(v, sizeof(RPC_CLIENT_ENUM_VLAN)); v->NumItem = PackGetNum(p, "NumItem"); v->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM *) * v->NumItem); for (i = 0;i < v->NumItem;i++) { RPC_CLIENT_ENUM_VLAN_ITEM *item = v->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM)); PackGetStrEx(p, "DeviceName", item->DeviceName, sizeof(item->DeviceName), i); item->Enabled = PackGetIntEx(p, "Enabled", i) ? true : false; PackGetStrEx(p, "MacAddress", item->MacAddress, sizeof(item->MacAddress), i); PackGetStrEx(p, "Version", item->Version, sizeof(item->Version), i); } } void OutRpcClientEnumVLan(PACK *p, RPC_CLIENT_ENUM_VLAN *v) { UINT i; // Validate arguments if (v == NULL || p == NULL) { return; } PackAddNum(p, "NumItem", v->NumItem); PackSetCurrentJsonGroupName(p, "VLanList"); for (i = 0;i < v->NumItem;i++) { RPC_CLIENT_ENUM_VLAN_ITEM *item = v->Items[i]; PackAddStrEx(p, "DeviceName", item->DeviceName, i, v->NumItem); PackAddIntEx(p, "Enabled", item->Enabled, i, v->NumItem); PackAddStrEx(p, "MacAddress", item->MacAddress, i, v->NumItem); PackAddStrEx(p, "Version", item->Version, i, v->NumItem); } PackSetCurrentJsonGroupName(p, NULL); } // CLIENT_OPTION void InRpcClientOption(CLIENT_OPTION *c, PACK *p) { // Validate arguments if (c == NULL || p == NULL) { return; } Zero(c, sizeof(CLIENT_OPTION)); PackGetUniStr(p, "AccountName", c->AccountName, sizeof(c->AccountName)); PackGetStr(p, "Hostname", c->Hostname, sizeof(c->Hostname)); // Extract hint string from hostname UINT i = SearchStrEx(c->Hostname, "/", 0, false); if (i != INFINITE) { StrCpy(c->HintStr, sizeof(c->HintStr), c->Hostname + i + 1); c->Hostname[i] = 0; } c->Port = PackGetInt(p, "Port"); c->PortUDP = PackGetInt(p, "PortUDP"); c->ProxyType = PackGetInt(p, "ProxyType"); c->ProxyPort = PackGetInt(p, "ProxyPort"); c->NumRetry = PackGetInt(p, "NumRetry"); c->RetryInterval = PackGetInt(p, "RetryInterval"); c->MaxConnection = PackGetInt(p, "MaxConnection"); c->AdditionalConnectionInterval = PackGetInt(p, "AdditionalConnectionInterval"); c->ConnectionDisconnectSpan = PackGetInt(p, "ConnectionDisconnectSpan"); c->HideStatusWindow = PackGetBool(p, "HideStatusWindow"); c->HideNicInfoWindow = PackGetBool(p, "HideNicInfoWindow"); c->DisableQoS = PackGetBool(p, "DisableQoS"); PackGetStr(p, "ProxyName", c->ProxyName, sizeof(c->ProxyName)); PackGetStr(p, "ProxyUsername", c->ProxyUsername, sizeof(c->ProxyUsername)); PackGetStr(p, "ProxyPassword", c->ProxyPassword, sizeof(c->ProxyPassword)); PackGetStr(p, "CustomHttpHeader", c->CustomHttpHeader, sizeof(c->CustomHttpHeader)); PackGetStr(p, "HubName", c->HubName, sizeof(c->HubName)); PackGetStr(p, "DeviceName", c->DeviceName, sizeof(c->DeviceName)); #if TYPE_BINDLOCALIP PackGetIp(p, "BindLocalIP", &c->BindLocalIP);// Source IP address for outgoing connection #endif c->UseEncrypt = PackGetInt(p, "UseEncrypt") ? true : false; c->UseCompress = PackGetInt(p, "UseCompress") ? true : false; c->HalfConnection = PackGetInt(p, "HalfConnection") ? true : false; c->NoRoutingTracking = PackGetInt(p, "NoRoutingTracking") ? true : false; c->RequireMonitorMode = PackGetBool(p, "RequireMonitorMode"); c->RequireBridgeRoutingMode = PackGetBool(p, "RequireBridgeRoutingMode"); c->FromAdminPack = PackGetBool(p, "FromAdminPack"); c->NoUdpAcceleration = PackGetBool(p, "NoUdpAcceleration"); PackGetData2(p, "HostUniqueKey", c->HostUniqueKey, SHA1_SIZE); } void OutRpcClientOption(PACK *p, CLIENT_OPTION *c) { // Validate arguments if (c == NULL || p == NULL) { return; } PackAddUniStr(p, "AccountName", c->AccountName); // Append hint string to hostname if (IsEmptyStr(c->HintStr)) { // No hint PackAddStr(p, "Hostname", c->Hostname); } else { char hostname[MAX_SIZE]; StrCpy(hostname, sizeof(hostname), c->Hostname); StrCat(hostname, sizeof(hostname), "/"); StrCat(hostname, sizeof(hostname), c->HintStr); PackAddStr(p, "Hostname", hostname); } PackAddStr(p, "ProxyName", c->ProxyName); PackAddStr(p, "ProxyUsername", c->ProxyUsername); PackAddStr(p, "ProxyPassword", c->ProxyPassword); PackAddStr(p, "CustomHttpHeader", c->CustomHttpHeader); PackAddStr(p, "HubName", c->HubName); PackAddStr(p, "DeviceName", c->DeviceName); PackAddInt(p, "Port", c->Port); PackAddInt(p, "PortUDP", c->PortUDP); PackAddInt(p, "ProxyType", c->ProxyType); PackAddInt(p, "ProxyPort", c->ProxyPort); PackAddInt(p, "NumRetry", c->NumRetry); PackAddInt(p, "RetryInterval", c->RetryInterval); PackAddInt(p, "MaxConnection", c->MaxConnection); PackAddBool(p, "UseEncrypt", c->UseEncrypt); PackAddBool(p, "UseCompress", c->UseCompress); PackAddBool(p, "HalfConnection", c->HalfConnection); PackAddBool(p, "NoRoutingTracking", c->NoRoutingTracking); PackAddInt(p, "AdditionalConnectionInterval", c->AdditionalConnectionInterval); PackAddInt(p, "ConnectionDisconnectSpan", c->ConnectionDisconnectSpan); PackAddBool(p, "HideStatusWindow", c->HideStatusWindow); PackAddBool(p, "HideNicInfoWindow", c->HideNicInfoWindow); PackAddBool(p, "RequireMonitorMode", c->RequireMonitorMode); PackAddBool(p, "RequireBridgeRoutingMode", c->RequireBridgeRoutingMode); PackAddBool(p, "DisableQoS", c->DisableQoS); PackAddBool(p, "FromAdminPack", c->FromAdminPack); PackAddBool(p, "NoUdpAcceleration", c->NoUdpAcceleration); PackAddData(p, "HostUniqueKey", c->HostUniqueKey, SHA1_SIZE); #if TYPE_BINDLOCALIP PackAddIp(p, "BindLocalIP", &c->BindLocalIP);// Source IP address for outgoing connection #endif } // CLIENT_AUTH void InRpcClientAuth(CLIENT_AUTH *c, PACK *p) { BUF *b; // Validate arguments if (c == NULL || p == NULL) { return; } Zero(c, sizeof(CLIENT_AUTH)); c->AuthType = PackGetInt(p, "AuthType"); PackGetStr(p, "Username", c->Username, sizeof(c->Username)); switch (c->AuthType) { case CLIENT_AUTHTYPE_ANONYMOUS: break; case CLIENT_AUTHTYPE_PASSWORD: if (PackGetDataSize(p, "HashedPassword") == SHA1_SIZE) { PackGetData(p, "HashedPassword", c->HashedPassword); } break; case CLIENT_AUTHTYPE_PLAIN_PASSWORD: PackGetStr(p, "PlainPassword", c->PlainPassword, sizeof(c->PlainPassword)); break; case CLIENT_AUTHTYPE_CERT: b = PackGetBuf(p, "ClientX"); if (b != NULL) { c->ClientX = BufToX(b, false); FreeBuf(b); } b = PackGetBuf(p, "ClientK"); if (b != NULL) { c->ClientK = BufToK(b, true, false, NULL); FreeBuf(b); } break; case CLIENT_AUTHTYPE_SECURE: PackGetStr(p, "SecurePublicCertName", c->SecurePublicCertName, sizeof(c->SecurePublicCertName)); PackGetStr(p, "SecurePrivateKeyName", c->SecurePrivateKeyName, sizeof(c->SecurePrivateKeyName)); break; case CLIENT_AUTHTYPE_OPENSSLENGINE: b = PackGetBuf(p, "ClientX"); if (b != NULL) { c->ClientX = BufToX(b, false); FreeBuf(b); } PackGetStr(p, "OpensslEnginePrivateKeyName", c->OpensslEnginePrivateKeyName, sizeof(c->OpensslEnginePrivateKeyName)); PackGetStr(p, "OpensslEngineName", c->OpensslEngineName, sizeof(c->OpensslEngineName)); break; } } void OutRpcClientAuth(PACK *p, CLIENT_AUTH *c) { BUF *b; // Validate arguments if (c == NULL || p == NULL) { return; } PackAddInt(p, "AuthType", c->AuthType); PackAddStr(p, "Username", c->Username); switch (c->AuthType) { case CLIENT_AUTHTYPE_ANONYMOUS: break; case CLIENT_AUTHTYPE_PASSWORD: PackAddData(p, "HashedPassword", c->HashedPassword, SHA1_SIZE); break; case CLIENT_AUTHTYPE_PLAIN_PASSWORD: PackAddStr(p, "PlainPassword", c->PlainPassword); break; case CLIENT_AUTHTYPE_CERT: b = XToBuf(c->ClientX, false); if (b != NULL) { PackAddBuf(p, "ClientX", b); FreeBuf(b); } b = KToBuf(c->ClientK, false, NULL); if (b != NULL) { PackAddBuf(p, "ClientK", b); FreeBuf(b); } break; case CLIENT_AUTHTYPE_SECURE: PackAddStr(p, "SecurePublicCertName", c->SecurePublicCertName); PackAddStr(p, "SecurePrivateKeyName", c->SecurePrivateKeyName); break; case CLIENT_AUTHTYPE_OPENSSLENGINE: b = XToBuf(c->ClientX, false); if (b != NULL) { PackAddBuf(p, "ClientX", b); FreeBuf(b); } PackAddStr(p, "OpensslEnginePrivateKeyName", c->OpensslEnginePrivateKeyName); PackAddStr(p, "OpensslEngineName", c->OpensslEngineName); break; } } // RPC_CLIENT_CREATE_ACCOUNT void InRpcClientCreateAccount(RPC_CLIENT_CREATE_ACCOUNT *c, PACK *p) { BUF *b; // Validate arguments if (c == NULL || p == NULL) { return; } Zero(c, sizeof(RPC_CLIENT_CREATE_ACCOUNT)); c->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION)); c->ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH)); InRpcClientOption(c->ClientOption, p); InRpcClientAuth(c->ClientAuth, p); c->StartupAccount = PackGetInt(p, "StartupAccount") ? true : false; c->CheckServerCert = PackGetInt(p, "CheckServerCert") ? true : false; c->RetryOnServerCert = PackGetInt(p, "RetryOnServerCert") ? true : false; c->AddDefaultCA = PackGetInt(p, "AddDefaultCA") ? true : false; b = PackGetBuf(p, "ServerCert"); if (b != NULL) { c->ServerCert = BufToX(b, false); FreeBuf(b); } PackGetData2(p, "ShortcutKey", c->ShortcutKey, sizeof(c->ShortcutKey)); } void OutRpcClientCreateAccount(PACK *p, RPC_CLIENT_CREATE_ACCOUNT *c) { BUF *b; // Validate arguments if (c == NULL || p == NULL) { return; } OutRpcClientOption(p, c->ClientOption); OutRpcClientAuth(p, c->ClientAuth); PackAddInt(p, "StartupAccount", c->StartupAccount); PackAddInt(p, "CheckServerCert", c->CheckServerCert); PackAddInt(p, "RetryOnServerCert", c->RetryOnServerCert); PackAddInt(p, "AddDefaultCA", c->AddDefaultCA); if (c->ServerCert != NULL) { b = XToBuf(c->ServerCert, false); if (b != NULL) { PackAddBuf(p, "ServerCert", b); FreeBuf(b); } } PackAddData(p, "ShortcutKey", c->ShortcutKey, sizeof(c->ShortcutKey)); } // RPC_CLIENT_ENUM_ACCOUNT void InRpcClientEnumAccount(RPC_CLIENT_ENUM_ACCOUNT *e, PACK *p) { UINT i; // Validate arguments if (e == NULL || p == NULL) { return; } Zero(e, sizeof(RPC_CLIENT_ENUM_ACCOUNT)); e->NumItem = PackGetNum(p, "NumItem"); e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_ACCOUNT_ITEM *) * e->NumItem); for (i = 0;i < e->NumItem;i++) { RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_ACCOUNT_ITEM)); PackGetUniStrEx(p, "AccountName", item->AccountName, sizeof(item->AccountName), i); PackGetStrEx(p, "UserName", item->UserName, sizeof(item->UserName), i); PackGetStrEx(p, "ServerName", item->ServerName, sizeof(item->ServerName), i); PackGetStrEx(p, "ProxyName", item->ProxyName, sizeof(item->ProxyName), i); PackGetStrEx(p, "DeviceName", item->DeviceName, sizeof(item->DeviceName), i); item->ProxyType = PackGetIntEx(p, "ProxyType", i); item->Active = PackGetIntEx(p, "Active", i) ? true : false; item->StartupAccount = PackGetIntEx(p, "StartupAccount", i) ? true : false; item->Connected = PackGetBoolEx(p, "Connected", i); item->Port = PackGetIntEx(p, "Port", i); PackGetStrEx(p, "HubName", item->HubName, sizeof(item->HubName), i); item->CreateDateTime = PackGetInt64Ex(p, "CreateDateTime", i); item->UpdateDateTime = PackGetInt64Ex(p, "UpdateDateTime", i); item->LastConnectDateTime = PackGetInt64Ex(p, "LastConnectDateTime", i); } } void OutRpcClientEnumAccount(PACK *p, RPC_CLIENT_ENUM_ACCOUNT *e) { UINT i; // Validate arguments if (e == NULL || p == NULL) { return; } PackAddNum(p, "NumItem", e->NumItem); PackSetCurrentJsonGroupName(p, "AccountList"); for (i = 0;i < e->NumItem;i++) { RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = e->Items[i]; PackAddUniStrEx(p, "AccountName", item->AccountName, i, e->NumItem); PackAddStrEx(p, "UserName", item->UserName, i, e->NumItem); PackAddStrEx(p, "ServerName", item->ServerName, i, e->NumItem); PackAddStrEx(p, "ProxyName", item->ProxyName, i, e->NumItem); PackAddStrEx(p, "DeviceName", item->DeviceName, i, e->NumItem); PackAddIntEx(p, "ProxyType", item->ProxyType, i, e->NumItem); PackAddIntEx(p, "Active", item->Active, i, e->NumItem); PackAddIntEx(p, "StartupAccount", item->StartupAccount, i, e->NumItem); PackAddBoolEx(p, "Connected", item->Connected, i, e->NumItem); PackAddIntEx(p, "Port", item->Port, i, e->NumItem); PackAddStrEx(p, "HubName", item->HubName, i, e->NumItem); PackAddTime64Ex(p, "CreateDateTime", item->CreateDateTime, i, e->NumItem); PackAddTime64Ex(p, "UpdateDateTime", item->UpdateDateTime, i, e->NumItem); PackAddTime64Ex(p, "LastConnectDateTime", item->LastConnectDateTime, i, e->NumItem); } PackSetCurrentJsonGroupName(p, NULL); } // RPC_CLIENT_DELETE_ACCOUNT void InRpcClientDeleteAccount(RPC_CLIENT_DELETE_ACCOUNT *a, PACK *p) { // Validate arguments if (a == NULL || p == NULL) { return; } Zero(a, sizeof(RPC_CLIENT_DELETE_ACCOUNT)); PackGetUniStr(p, "AccountName", a->AccountName, sizeof(a->AccountName)); } void OutRpcClientDeleteAccount(PACK *p, RPC_CLIENT_DELETE_ACCOUNT *a) { // Validate arguments if (a == NULL || p == NULL) { return; } PackAddUniStr(p, "AccountName", a->AccountName); } // RPC_RENAME_ACCOUNT void InRpcRenameAccount(RPC_RENAME_ACCOUNT *a, PACK *p) { // Validate arguments if (a == NULL || p == NULL) { return; } Zero(a, sizeof(RPC_RENAME_ACCOUNT)); PackGetUniStr(p, "OldName", a->OldName, sizeof(a->OldName)); PackGetUniStr(p, "NewName", a->NewName, sizeof(a->NewName)); } void OutRpcRenameAccount(PACK *p, RPC_RENAME_ACCOUNT *a) { // Validate arguments if (a == NULL || p == NULL) { return; } PackAddUniStr(p, "OldName", a->OldName); PackAddUniStr(p, "NewName", a->NewName); } // RPC_CLIENT_GET_ACCOUNT void InRpcClientGetAccount(RPC_CLIENT_GET_ACCOUNT *c, PACK *p) { BUF *b; // Validate arguments if (c == NULL || p == NULL) { return; } Zero(c, sizeof(RPC_CLIENT_GET_ACCOUNT)); c->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION)); c->ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH)); PackGetUniStr(p, "AccountName", c->AccountName, sizeof(c->AccountName)); c->StartupAccount = PackGetInt(p, "StartupAccount") ? true : false; c->CheckServerCert = PackGetInt(p, "CheckServerCert") ? true : false; c->RetryOnServerCert = PackGetInt(p, "RetryOnServerCert") ? true : false; c->AddDefaultCA = PackGetInt(p, "AddDefaultCA") ? true : false; b = PackGetBuf(p, "ServerCert"); if (b != NULL) { c->ServerCert = BufToX(b, false); FreeBuf(b); } InRpcClientOption(c->ClientOption, p); InRpcClientAuth(c->ClientAuth, p); c->CreateDateTime = PackGetInt64(p, "CreateDateTime"); c->UpdateDateTime = PackGetInt64(p, "UpdateDateTime"); c->LastConnectDateTime = PackGetInt64(p, "LastConnectDateTime"); PackGetData2(p, "ShortcutKey", c->ShortcutKey, SHA1_SIZE); } void OutRpcClientGetAccount(PACK *p, RPC_CLIENT_GET_ACCOUNT *c) { BUF *b; // Validate arguments if (c == NULL || p == NULL) { return; } PackAddUniStr(p, "AccountName", c->AccountName); PackAddInt(p, "StartupAccount", c->StartupAccount); PackAddInt(p, "CheckServerCert", c->CheckServerCert); PackAddInt(p, "RetryOnServerCert", c->RetryOnServerCert); PackAddInt(p, "AddDefaultCA", c->AddDefaultCA); if (c->ServerCert != NULL) { b = XToBuf(c->ServerCert, false); if (b != NULL) { PackAddBuf(p, "ServerCert", b); FreeBuf(b); } } OutRpcClientOption(p, c->ClientOption); OutRpcClientAuth(p, c->ClientAuth); PackAddData(p, "ShortcutKey", c->ShortcutKey, SHA1_SIZE); PackAddTime64(p, "CreateDateTime", c->CreateDateTime); PackAddTime64(p, "UpdateDateTime", c->UpdateDateTime); PackAddTime64(p, "LastConnectDateTime", c->LastConnectDateTime); } // RPC_CLIENT_CONNECT void InRpcClientConnect(RPC_CLIENT_CONNECT *c, PACK *p) { // Validate arguments if (c == NULL || p == NULL) { return; } Zero(c, sizeof(RPC_CLIENT_CONNECT)); PackGetUniStr(p, "AccountName", c->AccountName, sizeof(c->AccountName)); } void OutRpcClientConnect(PACK *p, RPC_CLIENT_CONNECT *c) { // Validate arguments if (c == NULL || p == NULL) { return; } PackAddUniStr(p, "AccountName", c->AccountName); } // POLICY void InRpcPolicy(POLICY *o, PACK *p) { POLICY *pol; // Validate arguments if (o == NULL || p == NULL) { return; } pol = PackGetPolicy(p); Copy(o, pol, sizeof(POLICY)); Free(pol); } void OutRpcPolicy(PACK *p, POLICY *o) { // Validate arguments if (o == NULL || p == NULL) { return; } PackAddPolicy(p, o); } // RPC_CLIENT_GET_CONNECTION_STATUS void InRpcClientGetConnectionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *s, PACK *p) { BUF *b; // Validate arguments if (s == NULL || p == NULL) { return; } Zero(s, sizeof(RPC_CLIENT_GET_CONNECTION_STATUS)); PackGetUniStr(p, "AccountName", s->AccountName, sizeof(s->AccountName)); PackGetStr(p, "ServerName", s->ServerName, sizeof(s->ServerName)); PackGetStr(p, "ServerProductName", s->ServerProductName, sizeof(s->ServerProductName)); PackGetStr(p, "ProtocolVersion", s->ProtocolName, sizeof(s->ProtocolName)); PackGetStr(p, "CipherName", s->CipherName, sizeof(s->CipherName)); PackGetStr(p, "SessionName", s->SessionName, sizeof(s->SessionName)); PackGetStr(p, "ConnectionName", s->ConnectionName, sizeof(s->ConnectionName)); if (PackGetDataSize(p, "SessionKey") == SHA1_SIZE) { PackGetData(p, "SessionKey", s->SessionKey); } s->SessionStatus = PackGetInt(p, "SessionStatus"); s->ServerPort = PackGetInt(p, "ServerPort"); s->ServerProductVer = PackGetInt(p, "ServerProductVer"); s->ServerProductBuild = PackGetInt(p, "ServerProductBuild"); s->NumConnectionsEstablished = PackGetInt(p, "NumConnectionsEstablished"); s->MaxTcpConnections = PackGetInt(p, "MaxTcpConnections"); s->NumTcpConnections = PackGetInt(p, "NumTcpConnections"); s->NumTcpConnectionsUpload = PackGetInt(p, "NumTcpConnectionsUpload"); s->NumTcpConnectionsDownload = PackGetInt(p, "NumTcpConnectionsDownload"); s->StartTime = PackGetInt64(p, "StartTime"); /* !!! Do not correct the spelling to keep the backward protocol compatibility !!! */ s->FirstConnectionEstablisiedTime = PackGetInt64(p, "FirstConnectionEstablisiedTime"); s->CurrentConnectionEstablishTime = PackGetInt64(p, "CurrentConnectionEstablishTime"); s->TotalSendSize = PackGetInt64(p, "TotalSendSize"); s->TotalRecvSize = PackGetInt64(p, "TotalRecvSize"); s->TotalSendSizeReal = PackGetInt64(p, "TotalSendSizeReal"); s->TotalRecvSizeReal = PackGetInt64(p, "TotalRecvSizeReal"); s->Active = PackGetInt(p, "Active") ? true : false; s->Connected = PackGetInt(p, "Connected") ? true : false; s->HalfConnection = PackGetInt(p, "HalfConnection") ? true : false; s->QoS = PackGetInt(p, "QoS") ? true : false; s->UseEncrypt = PackGetInt(p, "UseEncrypt") ? true : false; s->UseCompress = PackGetInt(p, "UseCompress") ? true : false; s->IsRUDPSession = PackGetInt(p, "IsRUDPSession") ? true : false; PackGetStr(p, "UnderlayProtocol", s->UnderlayProtocol, sizeof(s->UnderlayProtocol)); PackGetStr(p, "ProtocolDetails", s->ProtocolDetails, sizeof(s->ProtocolDetails)); s->IsUdpAccelerationEnabled = PackGetInt(p, "IsUdpAccelerationEnabled") ? true : false; s->IsUsingUdpAcceleration = PackGetInt(p, "IsUsingUdpAcceleration") ? true : false; s->IsBridgeMode = PackGetBool(p, "IsBridgeMode"); s->IsMonitorMode = PackGetBool(p, "IsMonitorMode"); s->VLanId = PackGetInt(p, "VLanId"); b = PackGetBuf(p, "ServerX"); if (b != NULL) { s->ServerX = BufToX(b, false); FreeBuf(b); } b = PackGetBuf(p, "ClientX"); if (b != NULL) { s->ClientX = BufToX(b, false); FreeBuf(b); } InRpcPolicy(&s->Policy, p); InRpcTraffic(&s->Traffic, p); } void OutRpcClientGetConnectionStatus(PACK *p, RPC_CLIENT_GET_CONNECTION_STATUS *c) { BUF *b; // Validate arguments if (p == NULL || c == NULL) { return; } PackAddUniStr(p, "AccountName", c->AccountName); PackAddStr(p, "ServerName", c->ServerName); PackAddStr(p, "ServerProductName", c->ServerProductName); PackAddStr(p, "ProtocolVersion", c->ProtocolName); PackAddStr(p, "CipherName", c->CipherName); PackAddStr(p, "SessionName", c->SessionName); PackAddStr(p, "ConnectionName", c->ConnectionName); PackAddData(p, "SessionKey", c->SessionKey, SHA1_SIZE); PackAddBool(p, "Active", c->Active); PackAddBool(p, "Connected", c->Connected); PackAddInt(p, "SessionStatus", c->SessionStatus); PackAddInt(p, "ServerPort", c->ServerPort); PackAddInt(p, "ServerProductVer", c->ServerProductVer); PackAddInt(p, "ServerProductBuild", c->ServerProductBuild); PackAddInt(p, "NumConnectionsEstablished", c->NumConnectionsEstablished); PackAddBool(p, "HalfConnection", c->HalfConnection); PackAddBool(p, "QoS", c->QoS); PackAddInt(p, "MaxTcpConnections", c->MaxTcpConnections); PackAddInt(p, "NumTcpConnections", c->NumTcpConnections); PackAddInt(p, "NumTcpConnectionsUpload", c->NumTcpConnectionsUpload); PackAddInt(p, "NumTcpConnectionsDownload", c->NumTcpConnectionsDownload); PackAddBool(p, "UseEncrypt", c->UseEncrypt); PackAddBool(p, "UseCompress", c->UseCompress); PackAddBool(p, "IsRUDPSession", c->IsRUDPSession); PackAddStr(p, "UnderlayProtocol", c->UnderlayProtocol); PackAddStr(p, "ProtocolDetails", c->ProtocolDetails); PackAddBool(p, "IsUdpAccelerationEnabled", c->IsUdpAccelerationEnabled); PackAddBool(p, "IsUsingUdpAcceleration", c->IsUsingUdpAcceleration); PackAddBool(p, "IsBridgeMode", c->IsBridgeMode); PackAddBool(p, "IsMonitorMode", c->IsMonitorMode); PackAddTime64(p, "StartTime", c->StartTime); PackAddTime64(p, "FirstConnectionEstablisiedTime", c->FirstConnectionEstablisiedTime); PackAddTime64(p, "CurrentConnectionEstablishTime", c->CurrentConnectionEstablishTime); PackAddInt64(p, "TotalSendSize", c->TotalSendSize); PackAddInt64(p, "TotalRecvSize", c->TotalRecvSize); PackAddInt64(p, "TotalSendSizeReal", c->TotalSendSizeReal); PackAddInt64(p, "TotalRecvSizeReal", c->TotalRecvSizeReal); PackAddInt(p, "VLanId", c->VLanId); OutRpcPolicy(p, &c->Policy); OutRpcTraffic(p, &c->Traffic); if (c->ServerX != NULL) { b = XToBuf(c->ServerX, false); PackAddBuf(p, "ServerX", b); FreeBuf(b); } if (c->ClientX != NULL) { b = XToBuf(c->ClientX, false); PackAddBuf(p, "ClientX", b); FreeBuf(b); } } // Notification main void CiNotifyMain(CLIENT *c, SOCK *s) { CANCEL *cancel; // Validate arguments if (c == NULL || s == NULL) { return; } // Register a Cancel cancel = NewCancel(); LockList(c->NotifyCancelList); { Add(c->NotifyCancelList, cancel); } UnlockList(c->NotifyCancelList); // Wait while (true) { char ch = '@'; SOCKSET set; InitSockSet(&set); AddSockSet(&set, s); Select(&set, INFINITE, cancel, NULL); if (c->Halt) { // Abort break; } // 1 byte transmission if (Send(s, &ch, 1, false) == 0) { // Disconnected break; } } // Disconnect Disconnect(s); // Unregister the Cancel LockList(c->NotifyCancelList); { Delete(c->NotifyCancelList, cancel); } UnlockList(c->NotifyCancelList); ReleaseCancel(cancel); } // RPC acceptance code void CiRpcAccepted(CLIENT *c, SOCK *s) { UCHAR hashed_password[SHA1_SIZE]; UINT rpc_mode; UINT retcode; RPC *rpc; // Validate arguments if (c == NULL || s == NULL) { return; } // Receive the RPC mode if (RecvAll(s, &rpc_mode, sizeof(UINT), false) == false) { return; } rpc_mode = Endian32(rpc_mode); if (rpc_mode == CLIENT_RPC_MODE_NOTIFY) { // Notification mode CiNotifyMain(c, s); return; } else if (rpc_mode == CLIENT_RPC_MODE_SHORTCUT || rpc_mode == CLIENT_RPC_MODE_SHORTCUT_DISCONNECT) { // Shortcut key received UCHAR key[SHA1_SIZE]; UINT err = ERR_NO_ERROR; if (RecvAll(s, key, SHA1_SIZE, false)) { UINT i; wchar_t title[MAX_ACCOUNT_NAME_LEN + 1]; bool ok = false; // Connect to the specified setting LockList(c->AccountList); { for (i = 0;i < LIST_NUM(c->AccountList);i++) { ACCOUNT *a = LIST_DATA(c->AccountList, i); Lock(a->lock); { if (Cmp(a->ShortcutKey, key, SHA1_SIZE) == 0) { ok = true; UniStrCpy(title, sizeof(title), a->ClientOption->AccountName); } } Unlock(a->lock); } } UnlockList(c->AccountList); if (ok == false) { err = ERR_ACCOUNT_NOT_FOUND; } else { RPC_CLIENT_CONNECT t; Zero(&t, sizeof(t)); UniStrCpy(t.AccountName, sizeof(t.AccountName), title); if (rpc_mode == CLIENT_RPC_MODE_SHORTCUT) { // Connect if (CtConnect(c, &t)) { err = ERR_NO_ERROR; } else { err = c->Err; } } else { // Connect if (CtDisconnect(c, &t, false)) { err = ERR_NO_ERROR; } else { err = c->Err; } } } err = Endian32(err); SendAll(s, &err, sizeof(UINT), false); (void)RecvAll(s, &err, sizeof(UINT), false); } return; } // Password reception if (RecvAll(s, hashed_password, SHA1_SIZE, false) == false) { return; } retcode = 0; // Password comparison if (Cmp(hashed_password, c->EncryptedPassword, SHA1_SIZE) != 0) { retcode = 1; } if (c->PasswordRemoteOnly && IsLocalHostIP(&s->RemoteIP)) { // If in a mode that requires a password only remote, // the password sent from localhost is considered to be always correct retcode = 0; } Lock(c->lock); { if (c->Config.AllowRemoteConfig == false) { // If the remote control is prohibited, // identify whether this connection is from remote if (IsLocalHostIP(&s->RemoteIP) == false) { retcode = 2; } } } Unlock(c->lock); retcode = Endian32(retcode); // Error code transmission if (SendAll(s, &retcode, sizeof(UINT), false) == false) { return; } if (retcode != 0) { // Disconnect due to an error return; } // Create a RPC server rpc = StartRpcServer(s, CiRpcDispatch, c); // RPC server operation RpcServer(rpc); // Release the RPC server EndRpc(rpc); } // RPC acceptance thread void CiRpcAcceptThread(THREAD *thread, void *param) { CLIENT_RPC_CONNECTION *conn; CLIENT *c; SOCK *s; // Validate arguments if (thread == NULL || param == NULL) { return; } conn = (CLIENT_RPC_CONNECTION *)param; s = conn->Sock; c = conn->Client; AddRef(s->ref); // Add to the RPC connection list LockList(c->RpcConnectionList); { Add(c->RpcConnectionList, conn); } UnlockList(c->RpcConnectionList); NoticeThreadInit(thread); // Main process CiRpcAccepted(c, s); // Release from the connection list LockList(c->RpcConnectionList); { Delete(c->RpcConnectionList, conn); } UnlockList(c->RpcConnectionList); ReleaseSock(conn->Sock); ReleaseThread(conn->Thread); Free(conn); Disconnect(s); ReleaseSock(s); } // RPC server thread void CiRpcServerThread(THREAD *thread, void *param) { CLIENT *c; SOCK *listener; UINT i; LIST *thread_list; // Validate arguments if (thread == NULL || param == NULL) { return; } c = (CLIENT *)param; // RPC connection list c->RpcConnectionList = NewList(NULL); // Open the port listener = NULL; for (i = CLIENT_CONFIG_PORT;i < (CLIENT_CONFIG_PORT + 5);i++) { listener = Listen(i); if (listener != NULL) { break; } } if (listener == NULL) { // Error Alert(CEDAR_PRODUCT_STR " VPN Client RPC Port Open Failed.", CEDAR_CLIENT_STR); return; } #ifdef OS_WIN32 MsRegWriteIntEx2(REG_LOCAL_MACHINE, CLIENT_WIN32_REGKEYNAME, CLIENT_WIN32_REGVALUE_PORT, i, false, true); MsRegWriteIntEx2(REG_LOCAL_MACHINE, CLIENT_WIN32_REGKEYNAME, CLIENT_WIN32_REGVALUE_PID, MsGetCurrentProcessId(), false, true); #endif // OS_WIN32 c->RpcListener = listener; AddRef(listener->ref); NoticeThreadInit(thread); while (true) { // Wait for client connection CLIENT_RPC_CONNECTION *conn; SOCK *s = Accept(listener); if (s == NULL) { // Stop break; } // Create a client processing thread conn = ZeroMalloc(sizeof(CLIENT_RPC_CONNECTION)); conn->Client = c; conn->Sock = s; AddRef(s->ref); conn->Thread = NewThread(CiRpcAcceptThread, (void *)conn); WaitThreadInit(conn->Thread); ReleaseSock(s); } // Release the listener ReleaseSock(listener); thread_list = NewListFast(NULL); // Set all the event notification LockList(c->NotifyCancelList); { UINT i; for (i = 0;i < LIST_NUM(c->NotifyCancelList);i++) { CANCEL *cancel = LIST_DATA(c->NotifyCancelList, i); Cancel(cancel); } } UnlockList(c->NotifyCancelList); // Disconnect all the connections of connected yet LockList(c->RpcConnectionList); { for (i = 0;i < LIST_NUM(c->RpcConnectionList);i++) { CLIENT_RPC_CONNECTION *cc = LIST_DATA(c->RpcConnectionList, i); AddRef(cc->Thread->ref); Add(thread_list, cc->Thread); Disconnect(cc->Sock); } } UnlockList(c->RpcConnectionList); for (i = 0;i < LIST_NUM(thread_list);i++) { THREAD *t = LIST_DATA(thread_list, i); WaitThread(t, INFINITE); ReleaseThread(t); } ReleaseList(c->RpcConnectionList); ReleaseList(thread_list); #ifdef OS_WIN32 MsRegDeleteValueEx2(REG_LOCAL_MACHINE, CLIENT_WIN32_REGKEYNAME, CLIENT_WIN32_REGVALUE_PORT, false, true); MsRegDeleteValueEx2(REG_LOCAL_MACHINE, CLIENT_WIN32_REGKEYNAME, CLIENT_WIN32_REGVALUE_PID, false, true); #endif // OS_WIN32 } // Start the Keep void CiInitKeep(CLIENT *c) { // Validate arguments if (c == NULL) { return; } c->Keep = StartKeep(); // Apply settings if (c->Config.UseKeepConnect) { KEEP *k = c->Keep; Lock(k->lock); { StrCpy(k->ServerName, sizeof(k->ServerName), c->Config.KeepConnectHost); k->ServerPort = c->Config.KeepConnectPort; k->Interval = c->Config.KeepConnectInterval * 1000; k->UdpMode = (c->Config.KeepConnectProtocol == CONNECTION_UDP) ? true : false; k->Enable = true; } Unlock(k->lock); } } // Stop the Keep void CiFreeKeep(CLIENT *c) { // Validate arguments if (c == NULL) { return; } StopKeep(c->Keep); c->Keep = NULL; } // Start the RPC void CiStartRpcServer(CLIENT *c) { // Validate arguments if (c == NULL) { return; } c->RpcThread = NewThread(CiRpcServerThread, (void *)c); WaitThreadInit(c->RpcThread); } // Stop the RPC void CiStopRpcServer(CLIENT *c) { // Validate arguments if (c == NULL) { return; } Disconnect(c->RpcListener); ReleaseSock(c->RpcListener); WaitThread(c->RpcThread, INFINITE); ReleaseThread(c->RpcThread); } // Wait for the next notification bool CcWaitNotify(NOTIFY_CLIENT *n) { UCHAR c; // Validate arguments if (n == NULL) { return false; } // 1 character reception if (RecvAll(n->Sock, &c, 1, false) == false) { // Disconnected return false; } return true; } // Connect as a notification client NOTIFY_CLIENT *CcConnectNotify(REMOTE_CLIENT *rc) { NOTIFY_CLIENT *n; SOCK *s; char tmp[MAX_SIZE]; UINT rpc_mode = 0; UINT port; // Validate arguments if (rc == NULL || rc->Rpc == NULL || rc->Rpc->Sock == NULL) { return NULL; } // Connect IPToStr(tmp, sizeof(tmp), &rc->Rpc->Sock->RemoteIP); port = rc->Rpc->Sock->RemotePort; s = Connect(tmp, port); if (s == NULL) { return NULL; } rpc_mode = Endian32(rpc_mode); if (SendAll(s, &rpc_mode, sizeof(rpc_mode), false) == false) { ReleaseSock(s); return NULL; } n = ZeroMalloc(sizeof(NOTIFY_CLIENT)); n->Sock = s; return n; } // Stop the notification client void CcStopNotify(NOTIFY_CLIENT *n) { // Validate arguments if (n == NULL) { return; } Disconnect(n->Sock); } // Delete the notification client void CcDisconnectNotify(NOTIFY_CLIENT *n) { // Validate arguments if (n == NULL) { return; } // Disconnect Disconnect(n->Sock); ReleaseSock(n->Sock); // Memory release Free(n); } // Disconnect the remote connection void CcDisconnectRpc(REMOTE_CLIENT *rc) { // Validate arguments if (rc == NULL) { return; } RpcFree(rc->Rpc); Free(rc); } // Connect to the client to start the shortcut connection setting UINT CcShortcut(UCHAR *key) { UINT ret; // Validate arguments if (key == NULL) { return ERR_INVALID_PARAMETER; } CcConnectRpcEx("localhost", NULL, NULL, NULL, key, &ret, false, 0); return ret; } // Disconnect the connected shortcut connection UINT CcShortcutDisconnect(UCHAR *key) { UINT ret; // Validate arguments if (key == NULL) { return ERR_INVALID_PARAMETER; } CcConnectRpcEx("localhost", NULL, NULL, NULL, key, &ret, true, 0); return ret; } // Connect to the remote client REMOTE_CLIENT *CcConnectRpc(char *server_name, char *password, bool *bad_pass, bool *no_remote, UINT wait_retry) { return CcConnectRpcEx(server_name, password, bad_pass, no_remote, NULL, NULL, false, wait_retry); } REMOTE_CLIENT *CcConnectRpcEx(char *server_name, char *password, bool *bad_pass, bool *no_remote, UCHAR *key, UINT *key_error_code, bool shortcut_disconnect, UINT wait_retry) { SOCK *s = NULL; UINT i; UINT retcode; UINT rpc_mode = CLIENT_RPC_MODE_MANAGEMENT; RPC *rpc; REMOTE_CLIENT *ret; UCHAR hash_password[SHA1_SIZE]; UINT port_start; UINT64 try_started = 0; bool ok; UINT reg_port = 0; UINT reg_pid = 0; // Validate arguments if (server_name == NULL) { return NULL; } if (password == NULL) { password = ""; } if (key_error_code != NULL) { *key_error_code = ERR_NO_ERROR; } if (bad_pass != NULL) { *bad_pass = false; } if (no_remote != NULL) { *no_remote = false; } #ifdef OS_WIN32 // read the current port number from the registry of the localhost if (StrCmpi(server_name, "localhost") == 0) { reg_port = MsRegReadIntEx2(REG_LOCAL_MACHINE, CLIENT_WIN32_REGKEYNAME, CLIENT_WIN32_REGVALUE_PORT, false, true); reg_pid = MsRegReadIntEx2(REG_LOCAL_MACHINE, CLIENT_WIN32_REGKEYNAME, CLIENT_WIN32_REGVALUE_PID, false, true); if (reg_pid != 0) { if (MsIsServiceRunning(GC_SVC_NAME_VPNCLIENT) == false) { reg_port = 0; } } else { reg_port = 0; } } if (reg_port != 0) { s = Connect(server_name, reg_port); if (s != NULL) { goto L_TRY; } } #endif // OS_WIN32 port_start = CLIENT_CONFIG_PORT - 1; RETRY: port_start++; if (port_start >= (CLIENT_CONFIG_PORT + 5)) { return NULL; } ok = false; while (true) { for (i = port_start;i < (CLIENT_CONFIG_PORT + 5);i++) { if (CheckTCPPort(server_name, i)) { ok = true; break; } } if (ok) { break; } if (wait_retry == 0) { break; } if (try_started == 0) { try_started = Tick64(); } if ((try_started + (UINT64)wait_retry) <= Tick64()) { break; } } if (ok == false) { if (key_error_code) { *key_error_code = ERR_CONNECT_FAILED; } return NULL; } port_start = i; s = Connect(server_name, i); if (s == NULL) { if (key_error_code) { *key_error_code = ERR_CONNECT_FAILED; } goto RETRY; } L_TRY: SetTimeout(s, 10000); Sha0(hash_password, password, StrLen(password)); if (key != NULL) { if (shortcut_disconnect == false) { rpc_mode = CLIENT_RPC_MODE_SHORTCUT; } else { rpc_mode = CLIENT_RPC_MODE_SHORTCUT_DISCONNECT; } } rpc_mode = Endian32(rpc_mode); SendAdd(s, &rpc_mode, sizeof(UINT)); if (key != NULL) { SendAdd(s, key, SHA1_SIZE); } else { SendAdd(s, hash_password, SHA1_SIZE); } if (SendNow(s, false) == false) { ReleaseSock(s); goto RETRY; } if (RecvAll(s, &retcode, sizeof(UINT), false) == false) { ReleaseSock(s); goto RETRY; } retcode = Endian32(retcode); if (retcode >= 1024) { ReleaseSock(s); goto RETRY; } if (key != NULL) { if (key_error_code) { *key_error_code = retcode; } SendAll(s, &retcode, sizeof(UINT), false); ReleaseSock(s); return NULL; } switch (retcode) { case 1: if (bad_pass != NULL) { *bad_pass = true; } break; case 2: if (no_remote != NULL) { *no_remote = true; } break; } if (retcode != 0) { ReleaseSock(s); return NULL; } SetTimeout(s, INFINITE); rpc = StartRpcClient(s, NULL); ReleaseSock(s); ret = ZeroMalloc(sizeof(REMOTE_CLIENT)); rpc->Param = ret; if (ret != NULL) { RPC_CLIENT_VERSION t; ret->Rpc = rpc; Zero(&t, sizeof(t)); CcGetClientVersion(ret, &t); ret->OsType = t.OsType; ret->Unix = OS_IS_UNIX(ret->OsType); ret->IsVgcSupported = t.IsVgcSupported; ret->ShowVgcLink = t.ShowVgcLink; StrCpy(ret->ClientId, sizeof(ret->ClientId), t.ClientId); } return ret; } // Get a RPC_CLIENT_GET_CONNECTION_STATUS from the session void CiGetSessionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *st, SESSION *s) { // Validate arguments if (st == NULL || s == NULL) { return; } Lock(s->lock); { // Operation flag st->Active = true; // Session status st->SessionStatus = s->ClientStatus; // Account name UniStrCpy(st->AccountName, sizeof(st->AccountName), s->ClientOption->AccountName); if (s->ClientStatus == CLIENT_STATUS_ESTABLISHED && s->Connection != NULL) { Lock(s->Connection->lock); { // Connected flag st->Connected = true; // Product name StrCpy(st->ServerProductName, sizeof(st->ServerProductName), s->Connection->ServerStr); // Version st->ServerProductVer = s->Connection->ServerVer; // Build Number st->ServerProductBuild = s->Connection->ServerBuild; // Server certificate st->ServerX = CloneX(s->Connection->ServerX); // Client certificate st->ClientX = CloneX(s->Connection->ClientX); // Connection completion time of this connection st->CurrentConnectionEstablishTime = TickToTime(s->CurrentConnectionEstablishTime); // Maximum number of the TCP connections st->MaxTcpConnections = s->MaxConnection; // Half-connection st->HalfConnection = s->HalfConnection; // VLAN st->VLanId = s->VLanId; // VoIP / QoS st->QoS = s->QoS; if (s->Connection->Protocol == CONNECTION_TCP) { UINT i; // Number of current TCP connections LockList(s->Connection->Tcp->TcpSockList); { st->NumTcpConnections = LIST_NUM(s->Connection->Tcp->TcpSockList); if (st->HalfConnection) { for (i = 0;i < st->NumTcpConnections;i++) { TCPSOCK *ts = LIST_DATA(s->Connection->Tcp->TcpSockList, i); if (ts->Direction & TCP_SERVER_TO_CLIENT) { st->NumTcpConnectionsDownload++; } else { st->NumTcpConnectionsUpload++; } } } } UnlockList(s->Connection->Tcp->TcpSockList); } // Use of encryption st->UseEncrypt = s->UseEncrypt; if (st->UseEncrypt) { StrCpy(st->CipherName, sizeof(st->CipherName), s->Connection->CipherName); StrCpy(st->ProtocolName, sizeof(st->ProtocolName), s->Connection->SslVersion); } // Use of compression st->UseCompress = s->UseCompress; // R-UDP st->IsRUDPSession = s->IsRUDPSession; // Physical communication protocol StrCpy(st->UnderlayProtocol, sizeof(st->UnderlayProtocol), s->UnderlayProtocol); // Protocol details StrCpy(st->ProtocolDetails, sizeof(st->ProtocolDetails), s->ProtocolDetails); Trim(st->ProtocolDetails); // UDP acceleration function if (s->IpcSessionShared != NULL && IsEmptyStr(s->IpcSessionShared->ProtocolDetails) == false) { char tmp[sizeof(s->IpcSessionShared->ProtocolDetails)]; StrCpy(tmp, sizeof(tmp), s->IpcSessionShared->ProtocolDetails); Trim(tmp); StrCat(st->ProtocolDetails, sizeof(st->ProtocolDetails), " "); StrCat(st->ProtocolDetails, sizeof(st->ProtocolDetails), tmp); st->IsUdpAccelerationEnabled = s->IpcSessionShared->EnableUdpAccel; st->IsUsingUdpAcceleration = s->IpcSessionShared->UsingUdpAccel; } else { st->IsUdpAccelerationEnabled = s->UseUdpAcceleration; st->IsUsingUdpAcceleration = s->IsUsingUdpAcceleration; } // Session key Copy(st->SessionKey, s->SessionKey, SHA1_SIZE); // Policy Copy(&st->Policy, s->Policy, sizeof(POLICY)); // Data size if (s->ServerMode == false) { st->TotalSendSize = s->TotalSendSize; st->TotalRecvSize = s->TotalRecvSize; st->TotalRecvSizeReal = s->TotalRecvSizeReal; st->TotalSendSizeReal = s->TotalSendSizeReal; } else { st->TotalSendSize = s->TotalRecvSize; st->TotalRecvSize = s->TotalSendSize; st->TotalRecvSizeReal = s->TotalSendSizeReal; st->TotalSendSizeReal = s->TotalRecvSizeReal; } // Session name StrCpy(st->SessionName, sizeof(st->SessionName), s->Name); // Connection name StrCpy(st->ConnectionName, sizeof(st->ConnectionName), s->Connection->Name); // Server name StrCpy(st->ServerName, sizeof(st->ServerName), s->Connection->ServerName); // Port number st->ServerPort = s->Connection->ServerPort; // Traffic data Lock(s->TrafficLock); { Copy(&st->Traffic, s->Traffic, sizeof(TRAFFIC)); } Unlock(s->TrafficLock); st->IsBridgeMode = s->IsBridgeMode; st->IsMonitorMode = s->IsMonitorMode; } Unlock(s->Connection->lock); } // Connection start time st->StartTime = TickToTime(s->CreatedTime); // Connection completion time of the first connection /* !!! Do not correct the spelling to keep the backward protocol compatibility !!! */ st->FirstConnectionEstablisiedTime = TickToTime(s->FirstConnectionEstablisiedTime); // Number of connections have been established so far st->NumConnectionsEstablished = s->NumConnectionsEstablished; } Unlock(s->lock); } // Get the connection status bool CtGetAccountStatus(CLIENT *c, RPC_CLIENT_GET_CONNECTION_STATUS *st) { // Validate arguments if (c == NULL || st == NULL) { return false; } LockList(c->AccountList); { ACCOUNT t, *r; // Search for account t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION)); UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), st->AccountName); r = Search(c->AccountList, &t); if (r == NULL) { // Specified account is not found UnlockList(c->AccountList); Free(t.ClientOption); CiSetError(c, ERR_ACCOUNT_NOT_FOUND); return false; } Free(t.ClientOption); Lock(r->lock); { Zero(st, sizeof(RPC_CLIENT_GET_CONNECTION_STATUS)); if (r->ClientSession != NULL) { SESSION *s = r->ClientSession; CiGetSessionStatus(st, s); } } Unlock(r->lock); } UnlockList(c->AccountList); return true; } // Release the connection status void CiFreeClientGetConnectionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *st) { // Validate arguments if (st == NULL) { return; } if (st->ServerX != NULL) { FreeX(st->ServerX); } if (st->ClientX != NULL) { FreeX(st->ClientX); } } // Verification procedure of the server certificate bool CiCheckCertProc(SESSION *s, CONNECTION *c, X *server_x, bool *expired) { #ifdef OS_WIN32 ACCOUNT *a; X *old_x = NULL; UI_CHECKCERT dlg; // Validate arguments if (s == NULL || c == NULL || server_x == NULL) { return false; } if (expired != NULL) { *expired = false; } Zero(&dlg, sizeof(dlg)); a = s->Account; if (a == NULL) { return false; } Lock(a->lock); { if (a->CheckServerCert == false) { // Not to validate the server certificate Unlock(a->lock); return true; } if (a->ServerCert != NULL) { old_x = CloneX(a->ServerCert); } } Unlock(a->lock); if (CheckXDateNow(server_x) == false) { // Expired if (old_x != NULL) { FreeX(old_x); } if (expired != NULL) { *expired = true; } return false; } if (old_x != NULL) { if (CompareX(old_x, server_x)) { // Matched exactly to the certificate that is already registered if (old_x != NULL) { FreeX(old_x); } return true; } else { dlg.DiffWarning = true; } } // Because this certificate can not be trusted, confirm to be trusted by showing a dialog box UniStrCpy(dlg.AccountName, sizeof(dlg.AccountName), a->ClientOption->AccountName); StrCpy(dlg.ServerName, sizeof(dlg.ServerName), a->ClientOption->Hostname); dlg.x = server_x; dlg.old_x = old_x; dlg.Session = s; AddRef(s->ref); CncCheckCert(s, &dlg); ReleaseSession(s); if (old_x != NULL) { FreeX(old_x); } if (dlg.Ok && dlg.SaveServerCert) { // Save the server certificate and trust it from the next time Lock(a->lock); { if (a->ServerCert != NULL) { FreeX(a->ServerCert); } a->ServerCert = CloneX(server_x); } Unlock(a->lock); CiSaveConfigurationFile(s->Cedar->Client); } return dlg.Ok; #else // OS_WIN32 ACCOUNT *a; X *old_x = NULL; // Validate arguments if (s == NULL || c == NULL || server_x == NULL) { return false; } if (expired != NULL) { *expired = false; } a = s->Account; if (a == NULL) { return false; } Lock(a->lock); { if (a->CheckServerCert == false) { // Not to validate the server certificate Unlock(a->lock); return true; } if (a->ServerCert != NULL) { old_x = CloneX(a->ServerCert); } } Unlock(a->lock); if (CheckXDateNow(server_x) == false) { // Expired if (old_x != NULL) { FreeX(old_x); } if (expired != NULL) { *expired = true; } return false; } if (old_x != NULL) { if (CompareX(old_x, server_x)) { // Exactly matched to the certificate that is already registered if (old_x != NULL) { FreeX(old_x); } return true; } else { // Mismatch if (old_x != NULL) { FreeX(old_x); } return false; } } return false; #endif // OS_WIN32 } // Signature procedure with a secure device bool CiSecureSignProc(SESSION *s, CONNECTION *c, SECURE_SIGN *sign) { // The UI is available in Win32 return CncSecureSignDlg(sign); } #ifdef OS_WIN32 // Signing procedure (for Win32) bool Win32CiSecureSign(SECURE_SIGN *sign) { bool ret = false; BUF *random; // Validate arguments if (sign == NULL) { return false; } random = NewBuf(); WriteBuf(random, sign->Random, SHA1_SIZE); // Batch processing { WINUI_SECURE_BATCH batch[] = { {WINUI_SECURE_READ_CERT, sign->SecurePublicCertName, true, NULL, NULL, NULL, NULL, NULL, NULL}, {WINUI_SECURE_SIGN_WITH_KEY, sign->SecurePrivateKeyName, true, random, NULL, NULL, NULL, NULL, NULL} }; if (SecureDeviceWindow(NULL, batch, sizeof(batch) / sizeof(batch[0]), sign->UseSecureDeviceId, sign->BitmapId) == false) { // Failure if (batch[0].OutputX != 0) { FreeX(batch[0].OutputX); } ret = false; } else { // Success ret = true; sign->ClientCert = batch[0].OutputX; Copy(sign->Signature, batch[1].OutputSign, MIN(sizeof(sign->Signature),sizeof(batch[1].OutputSign))); } } FreeBuf(random); return ret; } #endif // OS_WIN32 // Disconnect bool CtDisconnect(CLIENT *c, RPC_CLIENT_CONNECT *connect, bool inner) { bool ret = false; ACCOUNT t, *r; SESSION *s = NULL; // Validate arguments if (c == NULL || connect == NULL) { return false; } LockList(c->AccountList); { // Search for account t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION)); UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), connect->AccountName); r = Search(c->AccountList, &t); if (r == NULL) { // Specified account isn't found UnlockList(c->AccountList); Free(t.ClientOption); CiSetError(c, ERR_ACCOUNT_NOT_FOUND); return false; } Free(t.ClientOption); Lock(r->lock); { if (r->ClientSession == NULL) { // Not connected CiSetError(c, ERR_ACCOUNT_INACTIVE); } else { s = r->ClientSession; AddRef(s->ref); // Disconnect complete r->ClientSession = NULL; ret = true; } } Unlock(r->lock); } UnlockList(c->AccountList); if (s != NULL) { // Disconnect the connection (Wait until the disconnection is complete) CLog(c, "LC_DISCONNECT", connect->AccountName); StopSession(s); ReleaseSession(s); } if (ret != false) { CiNotify(c); } return ret; } // Connect bool CtConnect(CLIENT *c, RPC_CLIENT_CONNECT *connect) { bool ret = false; RPC_CLIENT_ENUM_VLAN t; // Validate arguments if (c == NULL || connect == NULL) { return false; } Lock(c->lockForConnect); { Zero(&t, sizeof(t)); if (CtEnumVLan(c, &t)) { if (t.NumItem == 0) { // Create a new virtual LAN card named "VPN" automatically RPC_CLIENT_CREATE_VLAN t; Zero(&t, sizeof(t)); StrCpy(t.DeviceName, sizeof(t.DeviceName), "VPN"); CtCreateVLan(c, &t); } CiFreeClientEnumVLan(&t); } } Unlock(c->lockForConnect); CiNormalizeAccountVLan(c); // Ensure successfully VPN communication by changing the irrational WCM settings in the case of Windows 8 or later CiDisableWcmNetworkMinimize(c); LockList(c->AccountList); { ACCOUNT t, *r; bool unix_disabled = false; // Search for account t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION)); UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), connect->AccountName); r = Search(c->AccountList, &t); if (r == NULL) { // Specified account isn't found UnlockList(c->AccountList); Free(t.ClientOption); CiSetError(c, ERR_ACCOUNT_NOT_FOUND); return false; } Free(t.ClientOption); #ifndef OS_WIN32 // Search for the virtual LAN card LockList(c->UnixVLanList); { UNIX_VLAN *v, t; Zero(&t, sizeof(t)); StrCpy(t.Name, sizeof(t.Name), r->ClientOption->DeviceName); v = Search(c->UnixVLanList, &t); if (v == NULL) { UnlockList(c->UnixVLanList); CiSetError(c, ERR_OBJECT_NOT_FOUND); return false; } unix_disabled = v->Enabled ? false : true; } UnlockList(c->UnixVLanList); #endif // OS_WIN32 Lock(r->lock); { bool already_used = false; UINT i; if (r->ClientSession != NULL) { // Already in connecting CiSetError(c, ERR_ACCOUNT_ACTIVE); } else if (r->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE && c->UseSecureDeviceId == 0) { // Secure device is not specified CiSetError(c, ERR_NO_SECURE_DEVICE_SPECIFIED); } #ifdef OS_WIN32 else if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, r->ClientOption->DeviceName) == false && MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, r->ClientOption->DeviceName) == false) { // Virtual LAN card can not be found CiSetError(c, ERR_VLAN_FOR_ACCOUNT_NOT_FOUND); CiNotify(c); CiSendGlobalPulse(c); } else if (MsIsVLanEnabled(r->ClientOption->DeviceName) == false) { // The virtual LAN card is disabled CiSetError(c, ERR_VLAN_FOR_ACCOUNT_DISABLED); CiNotify(c); CiSendGlobalPulse(c); } #else // OS_WIN32 else if (unix_disabled) { // The virtual LAN card is disabled CiSetError(c, ERR_VLAN_FOR_ACCOUNT_DISABLED); CiNotify(c); CiSendGlobalPulse(c); } #endif // OS_WIN32 else { // Check whether the virtual LAN card is being used by a different account already for (i = 0;i < LIST_NUM(c->AccountList);i++) { ACCOUNT *a = LIST_DATA(c->AccountList, i); if (a != r) { if (StrCmpi(a->ClientOption->DeviceName, r->ClientOption->DeviceName) == 0) { if (a->ClientSession != NULL) { already_used = true; break; } } } } if (already_used) { CiSetError(c, ERR_VLAN_FOR_ACCOUNT_USED); } else { // Start the connection PACKET_ADAPTER *pa = VLanGetPacketAdapter(); if (r->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE) { // Register a procedure for secure device authentication r->ClientAuth->SecureSignProc = CiSecureSignProc; } else if (r->ClientAuth->AuthType == CLIENT_AUTHTYPE_OPENSSLENGINE) { /* r->ClientAuth->ClientK = OpensslEngineToK("asdf"); */ r->ClientAuth->SecureSignProc = NULL; } else { r->ClientAuth->SecureSignProc = NULL; } if (r->CheckServerCert) { // Register a procedure to validate the server certificate r->ClientAuth->CheckCertProc = CiCheckCertProc; } else { r->ClientAuth->CheckCertProc = NULL; } r->StatusPrinter = CiClientStatusPrinter; r->LastConnectDateTime = SystemTime64(); CLog(c, "LC_CONNECT", connect->AccountName); r->ClientSession = NewClientSessionEx(c->Cedar, r->ClientOption, r->ClientAuth, pa, r); Notify(r->ClientSession, CLIENT_NOTIFY_ACCOUNT_CHANGED); ret = true; } } } Unlock(r->lock); } UnlockList(c->AccountList); CiSaveConfigurationFile(c); return ret; } // Put all unused TUN interfaces down // Requires account and VLan lists of the CLIENT argument to be already locked bool CtVLansDown(CLIENT *c) { #if defined(UNIX_LINUX) || defined(UNIX_BSD) int i; LIST *tmpVLanList; UNIX_VLAN t, *r; bool result = true; if (c == NULL) { return false; } tmpVLanList = CloneList(c->UnixVLanList); if (tmpVLanList == NULL) { return false; } // Remove from tmpVLanList all VLans corresponding to active sessions for (i = 0; i < LIST_NUM(c->AccountList); ++i) { ACCOUNT *a = LIST_DATA(c->AccountList, i); if (a->ClientSession == NULL) { continue; } Zero(&t, sizeof(t)); StrCpy(t.Name, sizeof(t.Name), a->ClientOption->DeviceName); r = Search(tmpVLanList, &t); Delete(tmpVLanList, r); } // Set down every VLan in tmpVLanList for (i = 0; i < LIST_NUM(tmpVLanList) && result; ++i) { r = LIST_DATA(tmpVLanList, i); result = UnixVLanSetState(r->Name, false); // [MP:] Should we report *critical* error on failure? } ReleaseList(tmpVLanList); return result; #else return true; #endif } // Put all TUN interfaces up // Requires VLan list of the CLIENT argument to be already locked bool CtVLansUp(CLIENT *c) { #if defined(UNIX_LINUX) || defined(UNIX_BSD) int i; UNIX_VLAN *r; if (c == NULL) { return false; } for (i = 0; i < LIST_NUM(c->UnixVLanList); ++i) { r = LIST_DATA(c->UnixVLanList, i); UnixVLanSetState(r->Name, true); } #endif return true; } // Get the account information bool CtGetAccount(CLIENT *c, RPC_CLIENT_GET_ACCOUNT *a) { // Validate arguments if (c == NULL || a == NULL) { return false; } LockList(c->AccountList); { ACCOUNT t, *r; // Search for account t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION)); UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->AccountName); r = Search(c->AccountList, &t); if (r == NULL) { // Specified account can not be found UnlockList(c->AccountList); Free(t.ClientOption); CiSetError(c, ERR_ACCOUNT_NOT_FOUND); return false; } Free(t.ClientOption); Lock(r->lock); { // Copy account name (restore the correct case) UniStrCpy(a->AccountName, sizeof(a->AccountName), r->ClientOption->AccountName); // Copy the client option if (a->ClientOption != NULL) { Free(a->ClientOption); } a->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION)); Copy(a->ClientOption, r->ClientOption, sizeof(CLIENT_OPTION)); // Copy the authentication data if (a->ClientAuth != NULL) { CiFreeClientAuth(a->ClientAuth); } a->ClientAuth = CopyClientAuth(r->ClientAuth); a->StartupAccount = r->StartupAccount; a->CheckServerCert = r->CheckServerCert; a->RetryOnServerCert = r->RetryOnServerCert; a->AddDefaultCA = r->AddDefaultCA; a->ServerCert = NULL; if (r->ServerCert != NULL) { a->ServerCert = CloneX(r->ServerCert); } // Shortcut Key Copy(a->ShortcutKey, r->ShortcutKey, SHA1_SIZE); a->CreateDateTime = r->CreateDateTime; a->LastConnectDateTime = r->LastConnectDateTime; a->UpdateDateTime = r->UpdateDateTime; } Unlock(r->lock); } UnlockList(c->AccountList); return true; } // Change the account name bool CtRenameAccount(CLIENT *c, RPC_RENAME_ACCOUNT *rename, bool inner) { bool ret; // Validate arguments if (c == NULL || rename == NULL) { return false; } ret = false; if (UniStrCmp(rename->NewName, rename->OldName) == 0) { // The name has not been changed return true; } LockList(c->AccountList); { ACCOUNT t, *r, *r2; if (UniStrLen(rename->NewName) == 0) { // Name is invalid CiSetError(c, ERR_INVALID_VALUE); UnlockList(c->AccountList); return false; } // Search for old account name t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION)); UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), rename->OldName); r = Search(c->AccountList, &t); if (r == NULL) { // Specified account can not be found UnlockList(c->AccountList); Free(t.ClientOption); CiSetError(c, ERR_ACCOUNT_NOT_FOUND); return false; } Free(t.ClientOption); // Search for a new account name t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION)); UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), rename->NewName); r2 = Search(c->AccountList, &t); if (r2 != NULL) { // Account with the specified name already exists UnlockList(c->AccountList); Free(t.ClientOption); CiSetError(c, ERR_ACCOUNT_ALREADY_EXISTS); return false; } Free(t.ClientOption); Lock(r->lock); { // Check the operating state of the account if (r->ClientSession != NULL) { // The Account is working Unlock(r->lock); UnlockList(c->AccountList); CiSetError(c, ERR_ACCOUNT_ACTIVE); return false; } // Update the account name UniStrCpy(r->ClientOption->AccountName, sizeof(r->ClientOption->AccountName), rename->NewName); CLog(c, "LC_RENAME_ACCOUNT", rename->OldName, rename->NewName); ret = true; } Unlock(r->lock); Sort(c->AccountList); } UnlockList(c->AccountList); CiSaveConfigurationFile(c); CiNotify(c); return ret; } // Set the client configuration bool CtSetClientConfig(CLIENT *c, CLIENT_CONFIG *o) { KEEP *k; // Validate arguments if (c == NULL || o == NULL) { return false; } if (o->UseKeepConnect) { if (IsEmptyStr(o->KeepConnectHost) || o->KeepConnectPort == 0 || o->KeepConnectPort >= 65536) { CiSetError(c, ERR_INVALID_PARAMETER); return false; } } Lock(c->lock); { Copy(&c->Config, o, sizeof(CLIENT_CONFIG)); } Unlock(c->lock); // Save the settings CiSaveConfigurationFile(c); // Apply the Keep Connect k = c->Keep; Lock(k->lock); { if (o->UseKeepConnect) { StrCpy(k->ServerName, sizeof(k->ServerName), c->Config.KeepConnectHost); k->ServerPort = c->Config.KeepConnectPort; k->Interval = c->Config.KeepConnectInterval * 1000; k->UdpMode = (c->Config.KeepConnectProtocol == CONNECTION_UDP) ? true : false; k->Enable = true; } else { k->Enable = false; } } Unlock(k->lock); // Apply TAP state LockList(c->AccountList); LockList(c->UnixVLanList); CtVLansDown(c); UnlockList(c->UnixVLanList); UnlockList(c->AccountList); return true; } // Get the network client configuration bool CtGetClientConfig(CLIENT *c, CLIENT_CONFIG *o) { // Validate arguments if (c == NULL || o == NULL) { return false; } Lock(c->lock); { Copy(o, &c->Config, sizeof(CLIENT_CONFIG)); } Unlock(c->lock); return true; } // Unset the startup attribute of the account bool CtRemoveStartupAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a) { bool ret; // Validate arguments if (c == NULL || a == NULL) { return false; } ret = false; LockList(c->AccountList); { ACCOUNT t, *r; // Search for an Account t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION)); UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->AccountName); r = Search(c->AccountList, &t); if (r == NULL) { // Specified account can not be found UnlockList(c->AccountList); Free(t.ClientOption); CiSetError(c, ERR_ACCOUNT_NOT_FOUND); return false; } Free(t.ClientOption); Lock(r->lock); { // Unset the startup account ret = true; r->StartupAccount = false; } Unlock(r->lock); } UnlockList(c->AccountList); if (ret) { CiSaveConfigurationFile(c); CiNotify(c); } return ret; } // Set the account as a start-up account bool CtSetStartupAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a, bool inner) { bool ret; // Validate arguments if (c == NULL || a == NULL) { return false; } ret = false; LockList(c->AccountList); { ACCOUNT t, *r; // Search for an account t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION)); UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->AccountName); r = Search(c->AccountList, &t); if (r == NULL) { // Specified account can not be found UnlockList(c->AccountList); Free(t.ClientOption); CiSetError(c, ERR_ACCOUNT_NOT_FOUND); return false; } Free(t.ClientOption); Lock(r->lock); { // Set to a start-up account ret = true; r->StartupAccount = true; } Unlock(r->lock); } UnlockList(c->AccountList); if (ret) { CiSaveConfigurationFile(c); CiNotify(c); } return ret; } // Delete the account bool CtDeleteAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a, bool inner) { bool ret; // Validate arguments if (c == NULL || a == NULL) { return false; } ret = false; if (c->Halt) { // Don't allow the removal of the account in the process of stopping CiSetError(c, ERR_INTERNAL_ERROR); return false; } LockList(c->AccountList); { ACCOUNT t, *r; // Search for an Account t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION)); UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->AccountName); r = Search(c->AccountList, &t); if (r == NULL) { // Specified account can not be found UnlockList(c->AccountList); Free(t.ClientOption); CiSetError(c, ERR_ACCOUNT_NOT_FOUND); return false; } Free(t.ClientOption); Lock(r->lock); { // Check the operating state of the account if (r->ClientSession != NULL) { // The account is active Unlock(r->lock); UnlockList(c->AccountList); CiSetError(c, ERR_ACCOUNT_ACTIVE); return false; } // Remove this account from the list Delete(c->AccountList, r); } Unlock(r->lock); // Free the memory of this account CiFreeAccount(r); CLog(c, "LC_DELETE_ACCOUNT", a->AccountName); ret = true; } UnlockList(c->AccountList); if (ret) { CiSaveConfigurationFile(c); CiNotify(c); } return ret; } // Enumeration of accounts bool CtEnumAccount(CLIENT *c, RPC_CLIENT_ENUM_ACCOUNT *e) { // Validate arguments if (c == NULL || e == NULL) { return false; } LockList(c->AccountList); { UINT i; // Number of accounts e->NumItem = LIST_NUM(c->AccountList); e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_ACCOUNT_ITEM *) * e->NumItem); for (i = 0;i < e->NumItem;i++) { ACCOUNT *a = LIST_DATA(c->AccountList, i); RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_ACCOUNT_ITEM)); e->Items[i] = item; // Account name UniStrCpy(item->AccountName, sizeof(item->AccountName), a->ClientOption->AccountName); // User name StrCpy(item->UserName, sizeof(item->UserName), a->ClientAuth->Username); // Server name StrCpy(item->ServerName, sizeof(item->ServerName), a->ClientOption->Hostname); // Append hint string to hostname if (IsEmptyStr(a->ClientOption->HintStr) == false) { StrCat(item->ServerName, sizeof(item->ServerName), "/"); StrCat(item->ServerName, sizeof(item->ServerName), a->ClientOption->HintStr); } // Proxy type item->ProxyType = a->ClientOption->ProxyType; // Device name StrCpy(item->DeviceName, sizeof(item->DeviceName), a->ClientOption->DeviceName); // Proxy information if (item->ProxyType != PROXY_DIRECT) { StrCpy(item->ProxyName, sizeof(item->ProxyName), a->ClientOption->ProxyName); } // Startup item->StartupAccount = a->StartupAccount; // Active flag item->Active = (a->ClientSession == NULL ? false : true); // Connection flag item->Connected = (item->Active == false) ? false : a->ClientSession->ConnectSucceed; // Port number item->Port = a->ClientOption->Port; // Virtual HUB name StrCpy(item->HubName, sizeof(item->HubName), a->ClientOption->HubName); item->CreateDateTime = a->CreateDateTime; item->LastConnectDateTime = a->LastConnectDateTime; item->UpdateDateTime = a->UpdateDateTime; } } UnlockList(c->AccountList); return true; } // Configure the account bool CtSetAccount(CLIENT *c, RPC_CLIENT_CREATE_ACCOUNT *a, bool inner) { // Validate arguments if (c == NULL || a == NULL) { return false; } // Check whether an account already exists LockList(c->AccountList); { ACCOUNT t, *ret; t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION)); UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->ClientOption->AccountName); ret = Search(c->AccountList, &t); if (ret == NULL) { // Not exist UnlockList(c->AccountList); Free(t.ClientOption); CiSetError(c, ERR_ACCOUNT_NOT_FOUND); return false; } Free(t.ClientOption); if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT) { if (a->ClientAuth->ClientX == NULL || a->ClientAuth->ClientX->is_compatible_bit == false || a->ClientAuth->ClientK == NULL) { // Client certificate is invalid UnlockList(c->AccountList); CiSetError(c, ERR_NOT_RSA_1024); return false; } } Lock(ret->lock); { #if 0 // Rewriting of the configuration is done even account running in the current version // (New setting isn't applied until connecting next time) if (ret->ClientSession != NULL) { // The account is operating Unlock(ret->lock); UnlockList(c->AccountList); CiSetError(c, ERR_ACCOUNT_ACTIVE); return false; } #endif // Delete the client authentication data CiFreeClientAuth(ret->ClientAuth); // Copy the client authentication data ret->ClientAuth = CopyClientAuth(a->ClientAuth); // Delete the client option Free(ret->ClientOption); // Copy the client option ret->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION)); Copy(ret->ClientOption, a->ClientOption, sizeof(CLIENT_OPTION)); ret->StartupAccount = a->StartupAccount; ret->CheckServerCert = a->CheckServerCert; ret->RetryOnServerCert = a->RetryOnServerCert; ret->AddDefaultCA = a->AddDefaultCA; if (a->ServerCert != NULL) { if (ret->ServerCert != NULL) { FreeX(ret->ServerCert); } ret->ServerCert = CloneX(a->ServerCert); } else { if (ret->ServerCert != NULL) { FreeX(ret->ServerCert); } ret->ServerCert = false; } ret->UpdateDateTime = SystemTime64(); } Unlock(ret->lock); } UnlockList(c->AccountList); CiSaveConfigurationFile(c); CiNotify(c); return true; } // Create an account bool CtCreateAccount(CLIENT *c, RPC_CLIENT_CREATE_ACCOUNT *a, bool inner) { // Validate arguments if (c == NULL || a == NULL) { return false; } // Check whether an account already exists LockList(c->AccountList); { ACCOUNT t, *ret, *new_account; t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION)); UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->ClientOption->AccountName); ret = Search(c->AccountList, &t); if (ret != NULL) { // Already exist UnlockList(c->AccountList); Free(t.ClientOption); CiSetError(c, ERR_ACCOUNT_ALREADY_EXISTS); return false; } Free(t.ClientOption); if (UniStrLen(a->ClientOption->AccountName) == 0) { // The name is invalid UnlockList(c->AccountList); CiSetError(c, ERR_INVALID_VALUE); return false; } if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT) { if (a->ClientAuth->ClientX == NULL || a->ClientAuth->ClientX->is_compatible_bit == false || a->ClientAuth->ClientK == NULL) { // The client certificate is invalid UnlockList(c->AccountList); CiSetError(c, ERR_NOT_RSA_1024); return false; } } // Add a new account new_account = ZeroMalloc(sizeof(ACCOUNT)); new_account->lock = NewLock(); // Copy the client authentication data new_account->ClientAuth = CopyClientAuth(a->ClientAuth); // Copy the client option new_account->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION)); Copy(new_account->ClientOption, a->ClientOption, sizeof(CLIENT_OPTION)); new_account->StartupAccount = a->StartupAccount; new_account->CheckServerCert = a->CheckServerCert; new_account->RetryOnServerCert = a->RetryOnServerCert; new_account->AddDefaultCA = a->AddDefaultCA; if (a->ServerCert != NULL) { new_account->ServerCert = CloneX(a->ServerCert); } // Shortcut Key if (IsZero(a->ShortcutKey, SHA1_SIZE)) { Rand(new_account->ShortcutKey, SHA1_SIZE); } else { Copy(new_account->ShortcutKey, a->ShortcutKey, SHA1_SIZE); } new_account->CreateDateTime = new_account->UpdateDateTime = SystemTime64(); // Insert into the list Insert(c->AccountList, new_account); CLog(c, "LC_NEW_ACCOUNT", a->ClientOption->AccountName); } UnlockList(c->AccountList); CiNormalizeAccountVLan(c); CiSaveConfigurationFile(c); CiNotify(c); return true; } // Release the account acquisition structure void CiFreeClientGetAccount(RPC_CLIENT_GET_ACCOUNT *a) { // Validate arguments if (a == NULL) { return; } // Release the account information if (a->ServerCert != NULL) { FreeX(a->ServerCert); } CiFreeClientAuth(a->ClientAuth); Free(a->ClientOption); } // Release the account creation structure void CiFreeClientCreateAccount(RPC_CLIENT_CREATE_ACCOUNT *a) { // Validate arguments if (a == NULL) { return; } // Release the account information if (a->ServerCert != NULL) { FreeX(a->ServerCert); } CiFreeClientAuth(a->ClientAuth); Free(a->ClientOption); } // Stop the virtual LAN card bool CtDisableVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *vlan) { UINT i; bool used; // Validate arguments if (c == NULL || vlan == NULL) { return false; } #ifndef OS_WIN32 #ifdef NO_VLAN if (GetOsInfo()->OsType == OSTYPE_MACOS_X) { // Can not be added or removed the virtual LAN card in MacOS X CiSetError(c, ERR_NOT_SUPPORTED); return false; } #endif // NO_VLAN // Check whether the virtual LAN card with the specified name is not // being used by one or more accounts used = false; LockList(c->AccountList); { for (i = 0;i < LIST_NUM(c->AccountList);i++) { ACCOUNT *a = LIST_DATA(c->AccountList, i); if (StrCmpi(a->ClientOption->DeviceName, vlan->DeviceName) == 0) { Lock(a->lock); { if (a->ClientSession != NULL) { used = true; } } Unlock(a->lock); } } } UnlockList(c->AccountList); // Search for the virtual LAN card LockList(c->UnixVLanList); { UNIX_VLAN *v, t; Zero(&t, sizeof(t)); StrCpy(t.Name, sizeof(t.Name), vlan->DeviceName); v = Search(c->UnixVLanList, &t); if (v == NULL) { UnlockList(c->UnixVLanList); CiSetError(c, ERR_OBJECT_NOT_FOUND); return false; } // Stop v->Enabled = false; } UnlockList(c->UnixVLanList); CiSaveConfigurationFile(c); CiNotify(c); CiSendGlobalPulse(c); return true; #else // OS_WIN32 // Check whether the virtual LAN card with the specified name is not // being used by one or more accounts used = false; LockList(c->AccountList); { for (i = 0;i < LIST_NUM(c->AccountList);i++) { ACCOUNT *a = LIST_DATA(c->AccountList, i); if (StrCmpi(a->ClientOption->DeviceName, vlan->DeviceName) == 0) { Lock(a->lock); { if (a->ClientSession != NULL) { used = true; } } Unlock(a->lock); } } } UnlockList(c->AccountList); #if 0 if (used) { // In using CiSetError(c, ERR_VLAN_IS_USED); return false; } #endif // Check whether the virtual LAN card are present if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, vlan->DeviceName) == false && MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, vlan->DeviceName) == false) { CiSetError(c, ERR_OBJECT_NOT_FOUND); CiNotify(c); CiSendGlobalPulse(c); return false; } if (MsIs64BitWindows() && Is32() && MsIsAdmin()) { // Execute the driver_installer to process since this Windows is 64 bit // but this code is 32 bit char tmp[MAX_SIZE]; Format(tmp, sizeof(tmp), "disablevlan %s", vlan->DeviceName); if (MsExecDriverInstaller(tmp) == false) { CiSetError(c, ERR_VLAN_INSTALL_ERROR); CiNotify(c); CiSendGlobalPulse(c); return false; } } else { // Stop the virtual LAN card if (MsDisableVLan(vlan->DeviceName) == false) { CiSetError(c, ERR_VLAN_INSTALL_ERROR); CiNotify(c); CiSendGlobalPulse(c); return false; } } CiNotify(c); CiSendGlobalPulse(c); return true; #endif // OS_WIN32 } // Start the virtual LAN card bool CtEnableVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *vlan) { // Validate arguments if (c == NULL || vlan == NULL) { return false; } #ifndef OS_WIN32 #ifdef NO_VLAN if (GetOsInfo()->OsType == OSTYPE_MACOS_X) { // Can not be added or removed the virtual LAN card in MacOS X CiSetError(c, ERR_NOT_SUPPORTED); return false; } #endif // NO_VLAN // Search the virtual LAN card LockList(c->UnixVLanList); { UNIX_VLAN *v, t; Zero(&t, sizeof(t)); StrCpy(t.Name, sizeof(t.Name), vlan->DeviceName); v = Search(c->UnixVLanList, &t); if (v == NULL) { UnlockList(c->UnixVLanList); CiSetError(c, ERR_OBJECT_NOT_FOUND); return false; } // Enable v->Enabled = true; } UnlockList(c->UnixVLanList); CiSaveConfigurationFile(c); CiNotify(c); CiSendGlobalPulse(c); return true; #else // OS_WIN32 // Check whether the virtual LAN card are present if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, vlan->DeviceName) == false && MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, vlan->DeviceName) == false) { CiSetError(c, ERR_OBJECT_NOT_FOUND); CiNotify(c); CiSendGlobalPulse(c); return false; } if (MsIs64BitWindows() && Is32() && MsIsAdmin()) { // Execute the driver_installer to process since this Windows is 64 bit // but this code is 32 bit char tmp[MAX_SIZE]; Format(tmp, sizeof(tmp), "enablevlan %s", vlan->DeviceName); if (MsExecDriverInstaller(tmp) == false) { CiSetError(c, ERR_VLAN_INSTALL_ERROR); CiNotify(c); CiSendGlobalPulse(c); return false; } } else { // Start the virtual LAN card if (MsEnableVLan(vlan->DeviceName) == false) { CiSetError(c, ERR_VLAN_INSTALL_ERROR); CiNotify(c); CiSendGlobalPulse(c); return false; } } CiNotify(c); CiSendGlobalPulse(c); return true; #endif // OS_WIN32 } // Delete the virtual LAN card bool CtDeleteVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *d) { UINT i; bool used; // Validate arguments if (c == NULL || d == NULL) { return false; } #ifndef OS_WIN32 #ifdef NO_VLAN if (GetOsInfo()->OsType == OSTYPE_MACOS_X) { // Can not be added or removed the virtual LAN card in MacOS X CiSetError(c, ERR_NOT_SUPPORTED); return false; } #endif // NO_VLAN // Check whether the virtual LAN card with the specified name is not // being used by one or more accounts used = false; LockList(c->AccountList); { for (i = 0;i < LIST_NUM(c->AccountList);i++) { ACCOUNT *a = LIST_DATA(c->AccountList, i); if (StrCmpi(a->ClientOption->DeviceName, d->DeviceName) == 0) { used = true; } } } UnlockList(c->AccountList); #if 0 if (used) { // In using CiSetError(c, ERR_VLAN_IS_USED); return false; } #endif // Search for the virtual LAN card LockList(c->UnixVLanList); { UNIX_VLAN *v, t; Zero(&t, sizeof(t)); StrCpy(t.Name, sizeof(t.Name), d->DeviceName); v = Search(c->UnixVLanList, &t); if (v == NULL) { UnlockList(c->UnixVLanList); CiSetError(c, ERR_OBJECT_NOT_FOUND); return false; } // Remove if (Delete(c->UnixVLanList, v)) { Free(v); } CLog(c, "LC_DELETE_VLAN", d->DeviceName); UnixVLanDelete(d->DeviceName); } UnlockList(c->UnixVLanList); CiNormalizeAccountVLan(c); CiSaveConfigurationFile(c); CiNotify(c); CiSendGlobalPulse(c); return true; #else // OS_WIN32 // Check whether the virtual LAN card are present if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, d->DeviceName) == false && MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, d->DeviceName) == false) { CiSetError(c, ERR_OBJECT_NOT_FOUND); return false; } // Check whether the virtual LAN card with the specified name is not // being used by one or more accounts used = false; LockList(c->AccountList); { for (i = 0;i < LIST_NUM(c->AccountList);i++) { ACCOUNT *a = LIST_DATA(c->AccountList, i); if (StrCmpi(a->ClientOption->DeviceName, d->DeviceName) == 0) { used = true; } } } UnlockList(c->AccountList); #if 0 if (used) { // In using CiSetError(c, ERR_VLAN_IS_USED); return false; } #endif if (MsIs64BitWindows() && Is32() && MsIsAdmin()) { // Execute the driver_installer to process since this Windows is 64 bit // but this code is 32 bit char tmp[MAX_SIZE]; Format(tmp, sizeof(tmp), "uninstvlan %s", d->DeviceName); if (MsExecDriverInstaller(tmp) == false) { CiSetError(c, ERR_VLAN_INSTALL_ERROR); return false; } } else { // Delete the virtual LAN card directly if (MsUninstallVLan(d->DeviceName) == false) { CiSetError(c, ERR_VLAN_INSTALL_ERROR); CiNotify(c); CiSendGlobalPulse(c); return false; } } CLog(c, "LC_DELETE_VLAN", d->DeviceName); CiNormalizeAccountVLan(c); CiNotify(c); CiSendGlobalPulse(c); return true; #endif // OS_WIN32 } // Get the name of the first VLAN char *CiGetFirstVLan(CLIENT *c) { char *ret = NULL; RPC_CLIENT_ENUM_VLAN t; // Validate arguments if (c == NULL) { return NULL; } Zero(&t, sizeof(t)); if (CtEnumVLan(c, &t) == false) { return NULL; } if (t.NumItem >= 1) { UINT i; char *tmp = t.Items[0]->DeviceName; for (i = 0;i < t.NumItem;i++) { if (t.Items[i]->Enabled) { tmp = t.Items[i]->DeviceName; } } ret = CopyStr(tmp); } CiFreeClientEnumVLan(&t); return ret; } // Enumerate virtual LAN cards bool CtEnumVLan(CLIENT *c, RPC_CLIENT_ENUM_VLAN *e) { UINT i; TOKEN_LIST *t; // Validate arguments if (c == NULL || e == NULL) { return false; } #ifndef OS_WIN32 LockList(c->UnixVLanList); { e->NumItem = LIST_NUM(c->UnixVLanList); e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM *) * e->NumItem); for (i = 0;i < e->NumItem;i++) { RPC_CLIENT_ENUM_VLAN_ITEM *item; UNIX_VLAN *v; v = LIST_DATA(c->UnixVLanList, i); e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM)); item = e->Items[i]; item->Enabled = v->Enabled; BinToStr(item->MacAddress, sizeof(item->MacAddress), v->MacAddress, 6); StrCpy(item->DeviceName, sizeof(item->DeviceName), v->Name); StrCpy(item->Version, sizeof(item->Version), c->Cedar->VerString); } } UnlockList(c->UnixVLanList); return true; #else // OS_WIN32 // Enumeration t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, VLAN_ADAPTER_NAME_OLD); if (t == NULL) { // Enumeration failure e->NumItem = 0; e->Items = ZeroMalloc(0); } else { // Enumeration success e->NumItem = t->NumTokens; e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM *) * e->NumItem); for (i = 0;i < e->NumItem;i++) { char *tmp; RPC_CLIENT_ENUM_VLAN_ITEM *item; e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM)); item = e->Items[i]; StrCpy(item->DeviceName, sizeof(item->DeviceName), t->Token[i]); item->Enabled = MsIsVLanEnabled(item->DeviceName); tmp = MsGetMacAddress(VLAN_ADAPTER_NAME_TAG, item->DeviceName); if (tmp == NULL) { tmp = MsGetMacAddress(VLAN_ADAPTER_NAME_TAG_OLD, item->DeviceName); } StrCpy(item->MacAddress, sizeof(item->MacAddress), tmp); Free(tmp); tmp = MsGetDriverVersion(VLAN_ADAPTER_NAME_TAG, item->DeviceName); if (tmp == NULL) { tmp = MsGetDriverVersion(VLAN_ADAPTER_NAME_TAG_OLD, item->DeviceName); } StrCpy(item->Version, sizeof(item->Version), tmp); Free(tmp); } FreeToken(t); } return true; #endif // OS_WIN32 } // Release the virtual LAN card enumeration void CiFreeClientEnumVLan(RPC_CLIENT_ENUM_VLAN *e) { UINT i; // Validate arguments if (e == NULL) { return; } for (i = 0;i < e->NumItem;i++) { Free(e->Items[i]); } Free(e->Items); } // Set the information about the virtual LAN card bool CtSetVLan(CLIENT *c, RPC_CLIENT_SET_VLAN *set) { // Validate arguments if (c == NULL || set == NULL) { return false; } #ifndef OS_WIN32 LockList(c->UnixVLanList); { UNIX_VLAN t, *r; Zero(&t, sizeof(t)); StrCpy(t.Name, sizeof(t.Name), set->DeviceName); r = Search(c->UnixVLanList, &t); if (r == NULL) { // Not exist CiSetError(c, ERR_VLAN_ALREADY_EXISTS); UnlockList(c->UnixVLanList); return false; } StrToMac(r->MacAddress, set->MacAddress); } UnlockList(c->UnixVLanList); CiSaveConfigurationFile(c); CiNotify(c); CiSendGlobalPulse(c); return true; #else // OS_WIN32 // Check whether the virtual LAN card with the specified name already exists if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, set->DeviceName) == false && MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, set->DeviceName) == false) { // Not exist CiSetError(c, ERR_OBJECT_NOT_FOUND); return false; } // Configuring MAC address MsSetMacAddress(VLAN_ADAPTER_NAME_TAG, set->DeviceName, set->MacAddress); MsSetMacAddress(VLAN_ADAPTER_NAME_TAG_OLD, set->DeviceName, set->MacAddress); CiNotify(c); CiSendGlobalPulse(c); return true; #endif // OS_WIN32 } // Get the information about the virtual LAN card bool CtGetVLan(CLIENT *c, RPC_CLIENT_GET_VLAN *get) { char *tmp; // Validate arguments if (c == NULL || get == NULL) { return false; } #ifndef OS_WIN32 // Unsupported CiSetError(c, ERR_NOT_SUPPORTED); return false; #else // OS_WIN32 // Check whether the virtual LAN card with the specified name already exists if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, get->DeviceName) == false && MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, get->DeviceName) == false) { // Not exist CiSetError(c, ERR_OBJECT_NOT_FOUND); return false; } // Activity get->Enabled = MsIsVLanEnabled(get->DeviceName); // MAC address tmp = MsGetMacAddress(VLAN_ADAPTER_NAME_TAG, get->DeviceName); if (tmp == NULL) { tmp = MsGetMacAddress(VLAN_ADAPTER_NAME_TAG_OLD, get->DeviceName); } StrCpy(get->MacAddress, sizeof(get->MacAddress), tmp); Free(tmp); // Version tmp = MsGetDriverVersion(VLAN_ADAPTER_NAME_TAG, get->DeviceName); if (tmp == NULL) { tmp = MsGetDriverVersion(VLAN_ADAPTER_NAME_TAG_OLD, get->DeviceName); } StrCpy(get->Version, sizeof(get->Version), tmp); Free(tmp); // File name tmp = MsGetDriverFileName(VLAN_ADAPTER_NAME_TAG, get->DeviceName); if (tmp == NULL) { tmp = MsGetDriverFileName(VLAN_ADAPTER_NAME_TAG_OLD, get->DeviceName); } StrCpy(get->FileName, sizeof(get->FileName), tmp); Free(tmp); // GUID tmp = MsGetNetworkAdapterGuid(VLAN_ADAPTER_NAME_TAG, get->DeviceName); if (tmp == NULL) { tmp = MsGetNetworkAdapterGuid(VLAN_ADAPTER_NAME_TAG_OLD, get->DeviceName); } StrCpy(get->Guid, sizeof(get->Guid), tmp); Free(tmp); return true; #endif // OS_WIN32 } #ifdef OS_WIN32 // Initialize the driver version information structure void CiInitDriverVerStruct(MS_DRIVER_VER *ver) { // Validate arguments if (ver == NULL) { return; } Zero(ver, sizeof(MS_DRIVER_VER)); ver->Year = BUILD_DATE_Y; ver->Month = BUILD_DATE_M; ver->Day = BUILD_DATE_D; ver->Major = CEDAR_VERSION_MAJOR; ver->Minor = CEDAR_VERSION_MINOR; ver->Build = CEDAR_VERSION_BUILD; } #endif // OS_WIN32 // Upgrade the virtual LAN card bool CtUpgradeVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *create) { bool use_old_name = false; #ifdef OS_WIN32 MS_DRIVER_VER ver; #endif // OS_WIN32 // Validate arguments if (c == NULL || create == NULL) { return false; } #ifndef OS_WIN32 // Always succeed return true; #else // OS_WIN32 CiInitDriverVerStruct(&ver); // Check whether the LAN card with the specified name already exists if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, create->DeviceName) == false && MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, create->DeviceName) == false) { // Not exist CiSetError(c, ERR_OBJECT_NOT_FOUND); CiNotify(c); CiSendGlobalPulse(c); return false; } if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, create->DeviceName)) { use_old_name = true; } // Perform the installation char tmp[MAX_SIZE]; Format(tmp, sizeof(tmp), "upgradevlan %s", create->DeviceName); if (CncExecDriverInstaller(tmp) == false) { // Installation Failed CiSetError(c, ERR_VLAN_INSTALL_ERROR); CiNotify(c); CiSendGlobalPulse(c); return false; } CLog(c, "LC_UPDATE_VLAN", create->DeviceName); CiNotify(c); CiSendGlobalPulse(c); return true; #endif // OS_WIN32 } // Create a virtual LAN card bool CtCreateVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *create) { TOKEN_LIST *t; UINT max_len; // Validate arguments if (c == NULL || create == NULL) { return false; } if (SearchStrEx(create->DeviceName, " ", 0, false) != INFINITE) { // Spaces in the name is not allowed CiSetError(c, ERR_INVALID_PARAMETER); return false; } #ifndef OS_WIN32 // Non-Win32 #ifdef NO_VLAN if (GetOsInfo()->OsType == OSTYPE_MACOS_X) { // A virtual LAN card can not be added or removed in MacOS X CiSetError(c, ERR_NOT_SUPPORTED); return false; } #endif // NO_VLAN // Check whether the specified name is valid or not if (IsSafeStr(create->DeviceName) == false) { // Name is invalid CiSetError(c, ERR_VLAN_INVALID_NAME); return false; } // Check whether the LAN card of the specified name already exists LockList(c->UnixVLanList); { UNIX_VLAN t, *r; Zero(&t, sizeof(t)); StrCpy(t.Name, sizeof(t.Name), create->DeviceName); r = Search(c->UnixVLanList, &t); if (r != NULL) { // Already exist CiSetError(c, ERR_VLAN_ALREADY_EXISTS); UnlockList(c->UnixVLanList); return false; } // Register r = ZeroMalloc(sizeof(UNIX_VLAN)); r->Enabled = true; GenMacAddress(r->MacAddress); StrCpy(r->Name, sizeof(r->Name), create->DeviceName); // Create a TUN if (UnixVLanCreate(r->Name, r->MacAddress, false) == false) { // Failure Free(r); CiSetError(c, ERR_VLAN_INSTALL_ERROR); UnlockList(c->UnixVLanList); return false; } CLog(c, "LC_CREATE_VLAN", create->DeviceName); Add(c->UnixVLanList, r); } UnlockList(c->UnixVLanList); CiNormalizeAccountVLan(c); CiNotify(c); CiSendGlobalPulse(c); CiSaveConfigurationFile(c); return true; #else // OS_WIN32 // Check whether the specified name is valid or not if (IsSafeStr(create->DeviceName) == false) { // Name is invalid CiSetError(c, ERR_VLAN_INVALID_NAME); return false; } max_len = MAX_DEVICE_NAME_LEN; if (StrLen(create->DeviceName) > max_len) { // Name is too long CiSetError(c, ERR_VLAN_INVALID_NAME); return false; } // Regulation in Windows 8 / 10 if (MsIsInfCatalogRequired()) { if (CiIsValidVLanRegulatedName(create->DeviceName) == false) { // Name is invalid CiSetError(c, ERR_VLAN_INVALID_NAME); return false; } } // Check whether the LAN card with the specified name already exists if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, create->DeviceName) || MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, create->DeviceName)) { // Already exist CiSetError(c, ERR_VLAN_ALREADY_EXISTS); return false; } // Perform the installation (Windows Vista) char tmp[MAX_SIZE]; Format(tmp, sizeof(tmp), "instvlan %s", create->DeviceName); if (CncExecDriverInstaller(tmp) == false) { CiSetError(c, ERR_VLAN_INSTALL_ERROR); CiNotify(c); CiSendGlobalPulse(c); return false; } t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, VLAN_ADAPTER_NAME_OLD); if (t->NumTokens == 1) { UINT i; // If the result of the installation, virtual LAN card is only one, // set virtual LAN card setting of all existing accounts to this virtual LAN card LockList(c->AccountList); { for (i = 0;i < LIST_NUM(c->AccountList);i++) { ACCOUNT *a = LIST_DATA(c->AccountList, i); Lock(a->lock); { if (a->ClientOption != NULL) { StrCpy(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName), create->DeviceName); } } Unlock(a->lock); } } UnlockList(c->AccountList); } FreeToken(t); CLog(c, "LC_CREATE_VLAN", create->DeviceName); CiNormalizeAccountVLan(c); CiNotify(c); CiSendGlobalPulse(c); CiSaveConfigurationFile(c); return true; #endif // OS_WIN32 } // Enumerate objects in the secure device bool CtEnumObjectInSecure(CLIENT *c, RPC_ENUM_OBJECT_IN_SECURE *e) { UINT i; // Validate arguments if (c == NULL || e == NULL) { return false; } e->NumItem = 5; e->ItemName = ZeroMalloc(sizeof(char *) * e->NumItem); e->ItemType = ZeroMalloc(sizeof(bool) * e->NumItem); for (i = 0;i < e->NumItem;i++) { char tmp[MAX_SIZE]; Format(tmp, sizeof(tmp), "Test Object %u", i); e->ItemName[i] = CopyStr(tmp); e->ItemType[i] = (i % 2 == 0) ? false : true; } return true; } // Get the secure device to be used bool CtGetUseSecure(CLIENT *c, RPC_USE_SECURE *sec) { // Validate arguments if (c == NULL || sec == NULL) { return false; } sec->DeviceId = c->UseSecureDeviceId; return true; } // Specifying a secure device to be used bool CtUseSecure(CLIENT *c, RPC_USE_SECURE *sec) { // Validate arguments if (c == NULL || sec == NULL) { return false; } // Do not check whether there is the specified device on the client manager /* if (CheckSecureDeviceId(sec->DeviceId)) { c->UseSecureDeviceId = sec->DeviceId; } else { CiSetError(c, ERR_OBJECT_NOT_FOUND); return false; } */ c->UseSecureDeviceId = sec->DeviceId; CiSaveConfigurationFile(c); return true; } // Enumeration of secure devices bool CtEnumSecure(CLIENT *c, RPC_CLIENT_ENUM_SECURE *e) { LIST *o; UINT i; // Validate arguments if (c == NULL || e == NULL) { return false; } o = GetSecureDeviceList(); e->NumItem = LIST_NUM(o); e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_SECURE_ITEM *) * e->NumItem); for (i = 0;i < LIST_NUM(o);i++) { RPC_CLIENT_ENUM_SECURE_ITEM *item = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_SECURE_ITEM)); SECURE_DEVICE *s = LIST_DATA(o, i); item->DeviceId = s->Id; StrCpy(item->DeviceName, sizeof(item->DeviceName), s->DeviceName); StrCpy(item->Manufacturer, sizeof(item->Manufacturer), s->Manufacturer); item->Type = s->Type; e->Items[i] = item; } return true; } // Release the secure device enumeration void CiFreeClientEnumSecure(RPC_CLIENT_ENUM_SECURE *e) { UINT i; // Validate arguments if (e == NULL) { return; } for (i = 0;i < e->NumItem;i++) { Free(e->Items[i]); } Free(e->Items); } // Release the RPC_GET_ISSUER void CiFreeGetIssuer(RPC_GET_ISSUER *a) { // Validate arguments if (a == NULL) { return; } if (a->issuer_x != NULL) { FreeX(a->issuer_x); } if (a->x != NULL) { FreeX(a->x); } } // Get the common proxy settings bool CtGetCommonProxySetting(CLIENT *c, INTERNET_SETTING *a) { // Validate arguments if (c == NULL || a == NULL) { return false; } Copy(a, &c->CommonProxySetting, sizeof(INTERNET_SETTING)); return true; } // Set the common proxy settings bool CtSetCommonProxySetting(CLIENT *c, INTERNET_SETTING *a) { // Validate arguments if (c == NULL || a == NULL) { return false; } Copy(&c->CommonProxySetting, a, sizeof(INTERNET_SETTING)); CiSaveConfigurationFile(c); return true; } // Get the issuer bool CtGetIssuer(CLIENT *c, RPC_GET_ISSUER *a) { X *x; // Validate arguments if (c == NULL || a == NULL) { return false; } x = FindCaSignedX(c->Cedar->CaList, a->x); if (x == NULL) { CiSetError(c, ERR_OBJECT_NOT_FOUND);; return false; } else { a->issuer_x = x; if (a->x != NULL) { FreeX(a->x); a->x = NULL; } return true; } } // Get the CA certificate bool CtGetCa(CLIENT *c, RPC_GET_CA *get) { bool ret = true; X *cert = NULL; // Validate arguments if (c == NULL || get == NULL) { return false; } LockList(c->Cedar->CaList); { UINT i; for (i = 0;i < LIST_NUM(c->Cedar->CaList);i++) { X *x = LIST_DATA(c->Cedar->CaList, i); if (POINTER_TO_KEY(x) == get->Key) { cert = CloneX(x); break; } } } UnlockList(c->Cedar->CaList); if (cert == NULL) { // Certificate does not exist ret = false; CiSetError(c, ERR_OBJECT_NOT_FOUND); } else { ret = true; get->x = cert; } return ret; } // Delete the CA certificate bool CtDeleteCa(CLIENT *c, RPC_CLIENT_DELETE_CA *p) { bool ret; // Validate arguments if (c == NULL || p == NULL) { return false; } ret = DeleteCa(c->Cedar, p->Key); if (ret == false) { CiSetError(c, ERR_OBJECT_NOT_FOUND); } CiSaveConfigurationFile(c); return ret; } // Add a CA certificate bool CtAddCa(CLIENT *c, RPC_CERT *cert) { // Validate arguments if (c == NULL || cert == NULL) { return false; } AddCa(c->Cedar, cert->x); CiSaveConfigurationFile(c); return true; } // Enumerate the trusted CA bool CtEnumCa(CLIENT *c, RPC_CLIENT_ENUM_CA *e) { // Validate arguments if (c == NULL || e == NULL) { return false; } Zero(e, sizeof(RPC_CLIENT_ENUM_CA)); LockList(c->Cedar->CaList); { UINT i; e->NumItem = LIST_NUM(c->Cedar->CaList); e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_CA_ITEM *) * e->NumItem); for (i = 0;i < e->NumItem;i++) { X *x = LIST_DATA(c->Cedar->CaList, i); e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_CA_ITEM)); GetAllNameFromNameEx(e->Items[i]->SubjectName, sizeof(e->Items[i]->SubjectName), x->subject_name); GetAllNameFromNameEx(e->Items[i]->IssuerName, sizeof(e->Items[i]->IssuerName), x->issuer_name); e->Items[i]->Expires = x->notAfter; e->Items[i]->Key = POINTER_TO_KEY(x); } } UnlockList(c->Cedar->CaList); return true; } // Release the CA enumeration void CiFreeClientEnumCa(RPC_CLIENT_ENUM_CA *e) { UINT i; // Validate arguments if (e == NULL) { return; } for (i = 0;i < e->NumItem;i++) { RPC_CLIENT_ENUM_CA_ITEM *ca = e->Items[i]; Free(ca); } Free(e->Items); } // Get the password setting bool CtGetPasswordSetting(CLIENT *c, RPC_CLIENT_PASSWORD_SETTING *a) { UCHAR hash[SHA1_SIZE]; // Validate arguments if (c == NULL || a == NULL) { return false; } Sha0(hash, "", 0); if (Cmp(hash, c->EncryptedPassword, SHA1_SIZE) == 0) { a->IsPasswordPresented = false; } else { a->IsPasswordPresented = true; } a->PasswordRemoteOnly = c->PasswordRemoteOnly; return true; } // Set the password bool CtSetPassword(CLIENT *c, RPC_CLIENT_PASSWORD *pass) { char *str; if (c == NULL) { return false; } str = pass->Password; if (StrCmp(str, "********") != 0) { // Hash the password Sha0(c->EncryptedPassword, str, StrLen(str)); } c->PasswordRemoteOnly = pass->PasswordRemoteOnly; CLog(c, "LC_SET_PASSWORD"); CiSaveConfigurationFile(c); return true; } void CiFreeIni(LIST *o) { // Validate arguments if (o == NULL) { return; } FreeIni(o); } // Read the custom.ini file LIST *CiLoadIni() { BUF *b = ReadDump(CLIENT_CUSTOM_INI_FILENAME); LIST *ini; if (b == NULL) { return NULL; } ini = ReadIni(b); FreeBuf(b); return ini; } // Reflect the settings of the custom.ini void CiLoadIniSettings(CLIENT *c) { LIST *o; //char *log; //char *config; if (c == NULL) { return; } o = CiLoadIni(); if (o == NULL) { return; } /*log = IniStrValue(o, "NoSaveLog"); config = IniStrValue(o, "NoSaveConfig"); if(StrCmpi(log, "true") == 0) { c->NoSaveLog = true; } if(StrCmpi(config, "true") == 0) { c->NoSaveConfig = true; }*/ c->NoSaveLog = ToBool(IniStrValue(o, "NoSaveLog")); c->NoSaveConfig = ToBool(IniStrValue(o, "NoSaveConfig")); CiFreeIni(o); } bool CiLoadConfigFilePathFromIni(char *path, UINT size) { char *tmp; LIST *o; bool ret = false; // Validate arguments if (path == NULL) { return false; } o = CiLoadIni(); if (o == NULL) { return false; } StrCpy(path, size, ""); tmp = IniStrValue(o, "ConfigPath"); NormalizePath(path, size, tmp); if (IsEmptyStr(path) == false) { ret = true; } else { ret = false; } CiFreeIni(o); return ret; } // Set the client error code void CiSetError(CLIENT *c, UINT err) { // Validate arguments if (c == NULL) { return; } c->Err = err; } // UNIX virtual LAN card comparison function int CiCompareUnixVLan(void *p1, void *p2) { UNIX_VLAN *v1, *v2; if (p1 == NULL || p2 == NULL) { return 0; } v1 = *(UNIX_VLAN **)p1; v2 = *(UNIX_VLAN **)p2; if (v1 == NULL || v2 == NULL) { return 0; } return StrCmpi(v1->Name, v2->Name); } // Modify the account settings that an incorrect VLAN name is specified void CiNormalizeAccountVLan(CLIENT *c) { bool b = false; char *name; UINT i; // Validate arguments if (c == NULL) { return; } name = CiGetFirstVLan(c); if (name != NULL) { LockList(c->AccountList); { for (i = 0;i < LIST_NUM(c->AccountList);i++) { ACCOUNT *a = LIST_DATA(c->AccountList, i); Lock(a->lock); { if (a->ClientOption != NULL) { if (CiIsVLan(c, a->ClientOption->DeviceName) == false) { StrCpy(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName), name); b = true; } } } Unlock(a->lock); } } UnlockList(c->AccountList); Free(name); } if (b) { CiNotify(c); CiSendGlobalPulse(c); CiSaveConfigurationFile(c); } } // Check whether a virtual LAN card of the specified name exists bool CiIsVLan(CLIENT *c, char *name) { // Validate arguments if (c == NULL || name == NULL) { return false; } #ifdef OS_WIN32 { TOKEN_LIST *t; UINT i; t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, VLAN_ADAPTER_NAME_OLD); if (t == NULL) { return false; } for (i = 0;i < t->NumTokens;i++) { if (StrCmpi(t->Token[i], name) == 0) { FreeToken(t); return true; } } FreeToken(t); return false; } #else // OS_WIN32 { UNIX_VLAN *v; UINT i; bool ret = false; LockList(c->UnixVLanList); { for (i = 0;i < LIST_NUM(c->UnixVLanList);i++) { v = (UNIX_VLAN *)LIST_DATA(c->UnixVLanList, i); if (StrCmpi(v->Name, name) == 0) { ret = true; } } } UnlockList(c->UnixVLanList); return ret; } #endif // OS_WIN32 } // If a non-existent virtual LAN card is specified in any Account, and only // one virtual LAN card is installed, set the virtual LAN card to the account void CiSetVLanToDefault(CLIENT *c) { char device_name[MAX_SIZE]; // Validate arguments if (c == NULL) { return; } #ifdef OS_WIN32 { TOKEN_LIST *t; t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, VLAN_ADAPTER_NAME_OLD); if (t == NULL) { return; } if (t->NumTokens != 1) { FreeToken(t); return; } StrCpy(device_name, sizeof(device_name), t->Token[0]); FreeToken(t); } #else // OS_WIN32 { UNIX_VLAN *v; LockList(c->UnixVLanList); if (LIST_NUM(c->UnixVLanList) != 1) { UnlockList(c->UnixVLanList); return; } v = LIST_DATA(c->UnixVLanList, 0); StrCpy(device_name, sizeof(device_name), v->Name); UnlockList(c->UnixVLanList); } #endif // OS_WIN32 { UINT i; LockList(c->AccountList); { for (i = 0;i < LIST_NUM(c->AccountList);i++) { ACCOUNT *a = LIST_DATA(c->AccountList, i); Lock(a->lock); { if (CiIsVLan(c, a->ClientOption->DeviceName) == false) { StrCpy(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName), device_name); } } Unlock(a->lock); } } UnlockList(c->AccountList); } } // Initialize the settings void CiInitConfiguration(CLIENT *c) { // Validate arguments if (c == NULL) { return; } #ifdef OS_UNIX // Initialize the VLAN UnixVLanInit(); #endif // OS_UNIX // Account list c->AccountList = NewList(CiCompareAccount); // Unix version VLAN list if (OS_IS_UNIX(GetOsInfo()->OsType)) { c->UnixVLanList = NewList(CiCompareUnixVLan); } // Read the configuration file CLog(c, "LC_LOAD_CONFIG_1"); if (CiLoadConfigurationFile(c) == false) { CLog(c, "LC_LOAD_CONFIG_3"); // Do the initial setup because the configuration file does not exist // Clear the password Sha0(c->EncryptedPassword, "", 0); // Initialize the client configuration // Disable remote management c->Config.AllowRemoteConfig = false; StrCpy(c->Config.KeepConnectHost, sizeof(c->Config.KeepConnectHost), CLIENT_DEFAULT_KEEPALIVE_HOST); c->Config.KeepConnectPort = CLIENT_DEFAULT_KEEPALIVE_PORT; c->Config.KeepConnectProtocol = CONNECTION_UDP; c->Config.KeepConnectInterval = CLIENT_DEFAULT_KEEPALIVE_INTERVAL; c->Config.UseKeepConnect = false; // Don't use the connection maintenance function by default in the Client // Eraser c->Eraser = NewEraser(c->Logger, 0); } else { CLog(c, "LC_LOAD_CONFIG_2"); } // Appropriate setting for virtual LAN card CiSetVLanToDefault(c); } // Release the settings void CiFreeConfiguration(CLIENT *c) { UINT i; // Validate arguments if (c == NULL) { return; } // Write to the configuration file CiSaveConfigurationFile(c); // Release the configuration file FreeCfgRw(c->CfgRw); // Release the account list for (i = 0;i < LIST_NUM(c->AccountList);i++) { ACCOUNT *a = LIST_DATA(c->AccountList, i); CiFreeAccount(a); } ReleaseList(c->AccountList); if (c->UnixVLanList != NULL) { // Release of UNIX version VLAN list for (i = 0;i < LIST_NUM(c->UnixVLanList);i++) { UNIX_VLAN *v = LIST_DATA(c->UnixVLanList, i); Free(v); } ReleaseList(c->UnixVLanList); } c->UnixVLanList = NULL; #ifdef OS_UNIX // Release the VLAN UnixVLanFree(); #endif // OS_UNIX } // Release the certificate data acquisition void CiFreeGetCa(RPC_GET_CA *a) { // Validate arguments if (a == NULL) { return; } FreeX(a->x); } // Release the client authentication data void CiFreeClientAuth(CLIENT_AUTH *auth) { // Validate arguments if (auth == NULL) { return; } if (auth->ClientX != NULL) { FreeX(auth->ClientX); } if (auth->ClientK != NULL) { FreeK(auth->ClientK); } Free(auth); } // Release the account void CiFreeAccount(ACCOUNT *a) { // Validate arguments if (a == NULL) { return; } // Release the lock DeleteLock(a->lock); // Release the client option Free(a->ClientOption); // Release the client authentication data CiFreeClientAuth(a->ClientAuth); if (a->ServerCert != NULL) { FreeX(a->ServerCert); } Free(a); } // Sort accounts int CiCompareAccount(void *p1, void *p2) { ACCOUNT *a1, *a2; if (p1 == NULL || p2 == NULL) { return 0; } a1 = *(ACCOUNT **)p1; a2 = *(ACCOUNT **)p2; if (a1 == NULL || a2 == NULL) { return 0; } return UniStrCmpi(a1->ClientOption->AccountName, a2->ClientOption->AccountName); } // Read the client configuration void CiLoadClientConfig(CLIENT_CONFIG *c, FOLDER *f) { // Validate arguments if (c == NULL || f == NULL) { return; } c->UseKeepConnect = CfgGetBool(f, "UseKeepConnect"); CfgGetStr(f, "KeepConnectHost", c->KeepConnectHost, sizeof(c->KeepConnectHost)); c->KeepConnectPort = CfgGetInt(f, "KeepConnectPort"); c->KeepConnectProtocol = CfgGetInt(f, "KeepConnectProtocol"); c->AllowRemoteConfig = CfgGetBool(f, "AllowRemoteConfig"); c->KeepConnectInterval = MAKESURE(CfgGetInt(f, "KeepConnectInterval"), KEEP_INTERVAL_MIN, KEEP_INTERVAL_MAX); c->NoChangeWcmNetworkSettingOnWindows8 = CfgGetBool(f, "NoChangeWcmNetworkSettingOnWindows8"); } // Read the client authentication data CLIENT_AUTH *CiLoadClientAuth(FOLDER *f) { CLIENT_AUTH *a; char *s; BUF *b; // Validate arguments if (f == NULL) { return NULL; } a = ZeroMalloc(sizeof(CLIENT_AUTH)); a->AuthType = CfgGetInt(f, "AuthType"); CfgGetStr(f, "Username", a->Username, sizeof(a->Username)); switch (a->AuthType) { case CLIENT_AUTHTYPE_ANONYMOUS: break; case CLIENT_AUTHTYPE_PASSWORD: CfgGetByte(f, "HashedPassword", a->HashedPassword, SHA1_SIZE); break; case CLIENT_AUTHTYPE_PLAIN_PASSWORD: b = CfgGetBuf(f, "EncryptedPassword"); if (b != NULL) { s = DecryptPassword(b); StrCpy(a->PlainPassword, sizeof(a->PlainPassword), s); Free(s); FreeBuf(b); } break; case CLIENT_AUTHTYPE_CERT: b = CfgGetBuf(f, "ClientCert"); if (b != NULL) { a->ClientX = BufToX(b, false); } FreeBuf(b); b = CfgGetBuf(f, "ClientKey"); if (b != NULL) { a->ClientK = BufToK(b, true, false, NULL); } FreeBuf(b); break; case CLIENT_AUTHTYPE_SECURE: CfgGetStr(f, "SecurePublicCertName", a->SecurePublicCertName, sizeof(a->SecurePublicCertName)); CfgGetStr(f, "SecurePrivateKeyName", a->SecurePrivateKeyName, sizeof(a->SecurePrivateKeyName)); break; case CLIENT_AUTHTYPE_OPENSSLENGINE: b = CfgGetBuf(f, "ClientCert"); if (b != NULL) { a->ClientX = BufToX(b, false); } FreeBuf(b); if (CfgGetStr(f, "OpensslEnginePrivateKeyName", a->OpensslEnginePrivateKeyName, sizeof(a->OpensslEnginePrivateKeyName))) { a->ClientK = OpensslEngineToK(a->OpensslEnginePrivateKeyName, a->OpensslEngineName); } CfgGetStr(f, "OpensslEngineName", a->OpensslEngineName, sizeof(a->OpensslEngineName)); break; } return a; } // Read the client option CLIENT_OPTION *CiLoadClientOption(FOLDER *f) { CLIENT_OPTION *o; char *s; BUF *b; // Validate arguments if (f == NULL) { return NULL; } o = ZeroMalloc(sizeof(CLIENT_OPTION)); CfgGetUniStr(f, "AccountName", o->AccountName, sizeof(o->AccountName)); CfgGetStr(f, "Hostname", o->Hostname, sizeof(o->Hostname)); // Extract hint string from hostname UINT i = SearchStrEx(o->Hostname, "/", 0, false); if (i != INFINITE) { StrCpy(o->HintStr, sizeof(o->HintStr), o->Hostname + i + 1); o->Hostname[i] = 0; } o->Port = CfgGetInt(f, "Port"); o->PortUDP = CfgGetInt(f, "PortUDP"); o->ProxyType = CfgGetInt(f, "ProxyType"); CfgGetStr(f, "ProxyName", o->ProxyName, sizeof(o->ProxyName)); o->ProxyPort = CfgGetInt(f, "ProxyPort"); CfgGetStr(f, "ProxyUsername", o->ProxyUsername, sizeof(o->ProxyUsername)); b = CfgGetBuf(f, "ProxyPassword"); s = DecryptPassword(b); StrCpy(o->ProxyPassword, sizeof(o->ProxyPassword), s); Free(s); FreeBuf(b); CfgGetStr(f, "CustomHttpHeader", o->CustomHttpHeader, sizeof(o->CustomHttpHeader)); o->NumRetry = CfgGetInt(f, "NumRetry"); o->RetryInterval = CfgGetInt(f, "RetryInterval"); CfgGetStr(f, "HubName", o->HubName, sizeof(o->HubName)); o->MaxConnection = CfgGetInt(f, "MaxConnection"); o->UseEncrypt = CfgGetBool(f, "UseEncrypt"); o->UseCompress = CfgGetBool(f, "UseCompress"); o->HalfConnection = CfgGetBool(f, "HalfConnection"); o->NoRoutingTracking = CfgGetBool(f, "NoRoutingTracking"); CfgGetStr(f, "DeviceName", o->DeviceName, sizeof(o->DeviceName)); o->AdditionalConnectionInterval = CfgGetInt(f, "AdditionalConnectionInterval"); o->HideStatusWindow = CfgGetBool(f, "HideStatusWindow"); o->HideNicInfoWindow = CfgGetBool(f, "HideNicInfoWindow"); o->ConnectionDisconnectSpan = CfgGetInt(f, "ConnectionDisconnectSpan"); o->RequireMonitorMode = CfgGetBool(f, "RequireMonitorMode"); o->RequireBridgeRoutingMode = CfgGetBool(f, "RequireBridgeRoutingMode"); o->DisableQoS = CfgGetBool(f, "DisableQoS"); o->FromAdminPack = CfgGetBool(f, "FromAdminPack"); o->NoUdpAcceleration = CfgGetBool(f, "NoUdpAcceleration"); CfgGetIp(f, "BindLocalIP", &o->BindLocalIP);// Source IP address for outgoing connection b = CfgGetBuf(f, "HostUniqueKey"); if (b != NULL) { if (b->Size == SHA1_SIZE) { Copy(o->HostUniqueKey, b->Buf, SHA1_SIZE); } FreeBuf(b); } return o; } // Read the account data ACCOUNT *CiLoadClientAccount(FOLDER *f) { ACCOUNT *a; FOLDER *client_option_folder, *client_auth_folder; BUF *b; char tmp[64]; // Validate arguments if (f == NULL) { return NULL; } client_option_folder = CfgGetFolder(f, "ClientOption"); if (client_option_folder != NULL) { // Compare whether it matches to the account name that is already registered } client_auth_folder = CfgGetFolder(f, "ClientAuth"); if (client_option_folder == NULL || client_auth_folder == NULL) { return NULL; } a = ZeroMalloc(sizeof(ACCOUNT)); a->lock = NewLock(); a->ClientOption = CiLoadClientOption(client_option_folder); a->ClientAuth = CiLoadClientAuth(client_auth_folder); a->StartupAccount = CfgGetBool(f, "StartupAccount"); a->CheckServerCert = CfgGetBool(f, "CheckServerCert"); a->RetryOnServerCert = CfgGetBool(f, "RetryOnServerCert"); a->AddDefaultCA = CfgGetBool(f, "AddDefaultCA"); a->CreateDateTime = CfgGetInt64(f, "CreateDateTime"); a->UpdateDateTime = CfgGetInt64(f, "UpdateDateTime"); a->LastConnectDateTime = CfgGetInt64(f, "LastConnectDateTime"); b = CfgGetBuf(f, "ServerCert"); if (b != NULL) { a->ServerCert = BufToX(b, false); FreeBuf(b); } if (CfgGetStr(f, "ShortcutKey", tmp, sizeof(tmp))) { BUF *b = StrToBin(tmp); if (b->Size == SHA1_SIZE) { Copy(a->ShortcutKey, b->Buf, SHA1_SIZE); } FreeBuf(b); } if (IsZero(a->ShortcutKey, SHA1_SIZE)) { Rand(a->ShortcutKey, SHA1_SIZE); } return a; } // Read the account database void CiLoadAccountDatabase(CLIENT *c, FOLDER *f) { TOKEN_LIST *t; UINT i; // Validate arguments if (c == NULL || f == NULL) { return; } t = CfgEnumFolderToTokenList(f); if (t == NULL) { return; } for (i = 0;i < t->NumTokens;i++) { FOLDER *ff = CfgGetFolder(f, t->Token[i]); if (ff != NULL) { ACCOUNT *a = CiLoadClientAccount(ff); if (a != NULL) { { Add(c->AccountList, a); } } } } Sort(c->AccountList); FreeToken(t); } // Read the root CA certificate void CiLoadCACert(CLIENT *c, FOLDER *f) { BUF *b; X *x; // Validate arguments if (c == NULL || f == NULL) { return; } b = CfgGetBuf(f, "X509"); if (b == NULL) { return; } x = BufToX(b, false); AddCa(c->Cedar, x); FreeX(x); FreeBuf(b); } // Read the root CA list void CiLoadCAList(CLIENT *c, FOLDER *f) { CEDAR *cedar; TOKEN_LIST *t; // Validate arguments if (c == NULL || f == NULL) { return; } t = CfgEnumFolderToTokenList(f); cedar = c->Cedar; LockList(cedar->CaList); { UINT i; for (i = 0;i < t->NumTokens;i++) { FOLDER *folder = CfgGetFolder(f, t->Token[i]); CiLoadCACert(c, folder); } } UnlockList(cedar->CaList); FreeToken(t); } // Read a VLAN void CiLoadVLan(CLIENT *c, FOLDER *f) { char tmp[MAX_SIZE]; UCHAR addr[6]; BUF *b; UNIX_VLAN *v; // Validate arguments if (c == NULL || f == NULL) { return; } if (CfgGetStr(f, "MacAddress", tmp, sizeof(tmp)) == false) { return; } b = StrToBin(tmp); if (b == NULL) { return; } if (b->Size != 6) { FreeBuf(b); return; } Copy(addr, b->Buf, 6); FreeBuf(b); if (IsZero(addr, 6)) { return; } v = ZeroMalloc(sizeof(UNIX_VLAN)); Copy(v->MacAddress, addr, 6); StrCpy(v->Name, sizeof(v->Name), f->Name); v->Enabled = CfgGetBool(f, "Enabled"); Add(c->UnixVLanList, v); #ifdef OS_UNIX UnixVLanCreate(v->Name, v->MacAddress, false); #endif // OS_UNIX } // Read a VLAN list void CiLoadVLanList(CLIENT *c, FOLDER *f) { TOKEN_LIST *t; // Validate arguments if (c == NULL || f == NULL) { return; } t = CfgEnumFolderToTokenList(f); LockList(c->UnixVLanList); { UINT i; for (i = 0;i < t->NumTokens;i++) { FOLDER *folder = CfgGetFolder(f, t->Token[i]); CiLoadVLan(c, folder); } } UnlockList(c->UnixVLanList); FreeToken(t); } // Read the configuration from the configuration file bool CiReadSettingFromCfg(CLIENT *c, FOLDER *root) { FOLDER *config; FOLDER *cert; FOLDER *db; FOLDER *vlan; FOLDER *cmsetting; FOLDER *proxy; char user_agent[MAX_SIZE]; // Validate arguments if (c == NULL || root == NULL) { return false; } // Initialize the setting if there isn't either of AccountDatabase and Config config = CfgGetFolder(root, "Config"); if (config == NULL) { return false; } db = CfgGetFolder(root, "AccountDatabase"); if (db == NULL) { return false; } cmsetting = CfgGetFolder(root, "ClientManagerSetting"); CiLoadClientConfig(&c->Config, config); proxy = CfgGetFolder(root, "CommonProxySetting"); if (proxy != NULL) { INTERNET_SETTING t; BUF *pw; // Proxy Setting Zero(&t, sizeof(t)); t.ProxyType = CfgGetInt(proxy, "ProxyType"); CfgGetStr(proxy, "ProxyHostName", t.ProxyHostName, sizeof(t.ProxyHostName)); t.ProxyPort = CfgGetInt(proxy, "ProxyPort"); CfgGetStr(proxy, "ProxyUsername", t.ProxyUsername, sizeof(t.ProxyUsername)); pw = CfgGetBuf(proxy, "ProxyPassword"); if (pw != NULL) { char *pw_str = DecryptPassword(pw); StrCpy(t.ProxyPassword, sizeof(t.ProxyPassword), pw_str); Free(pw_str); FreeBuf(pw); } CfgGetStr(proxy, "CustomHttpHeader", t.CustomHttpHeader, sizeof(t.CustomHttpHeader)); Copy(&c->CommonProxySetting, &t, sizeof(INTERNET_SETTING)); } // Eraser c->Eraser = NewEraser(c->Logger, CfgGetInt64(config, "AutoDeleteCheckDiskFreeSpaceMin")); if (OS_IS_UNIX(GetOsInfo()->OsType) #ifdef NO_VLAN && GetOsInfo()->OsType != OSTYPE_MACOS_X #endif // NO_VLAN ) { // Read the UNIX version virtual LAN card list (except MacOS) vlan = CfgGetFolder(root, "UnixVLan"); if (vlan != NULL) { CiLoadVLanList(c, vlan); } } #ifdef NO_VLAN if (GetOsInfo()->OsType == OSTYPE_MACOS_X) { #ifdef OS_UNIX UNIX_VLAN *uv; // Create a Tap for MacOS X if (UnixVLanCreate(CLIENT_MACOS_TAP_NAME, NULL, false) == false) { // Fail (abort) CLog(c, "LC_TAP_NOT_FOUND"); Alert("tun/tap driver not found.", NULL); exit(0); } uv = ZeroMalloc(sizeof(UNIX_VLAN)); uv->Enabled = true; StrCpy(uv->Name, sizeof(uv->Name), CLIENT_MACOS_TAP_NAME); Add(c->UnixVLanList, uv); #endif // OS_UNIX } #endif // NO_VLAN CiLoadAccountDatabase(c, db); if (CfgGetByte(root, "EncryptedPassword", c->EncryptedPassword, SHA1_SIZE) == false) { Sha0(c->EncryptedPassword, "", 0); } c->PasswordRemoteOnly = CfgGetBool(root, "PasswordRemoteOnly"); c->UseSecureDeviceId = CfgGetInt(root, "UseSecureDeviceId"); if (CfgGetStr(root, "UserAgent", user_agent, sizeof(user_agent))) { if (IsEmptyStr(user_agent) == false) { Free(c->Cedar->HttpUserAgent); c->Cedar->HttpUserAgent = CopyStr(user_agent); } } cert = CfgGetFolder(root, "RootCA"); if (cert != NULL) { CiLoadCAList(c, cert); } c->DontSavePassword = CfgGetBool(root, "DontSavePassword"); if (cmsetting != NULL) { UINT ostype = GetOsInfo()->OsType; // CM_SETTING CM_SETTING *s = c->CmSetting; s->EasyMode = CfgGetBool(cmsetting, "EasyMode"); s->LockMode = CfgGetBool(cmsetting, "LockMode"); CfgGetByte(cmsetting, "HashedPassword", s->HashedPassword, sizeof(s->HashedPassword)); } return true; } // Read the configuration file bool CiLoadConfigurationFile(CLIENT *c) { bool ret; FOLDER *root; char path[MAX_SIZE]; // Validate arguments if (c == NULL) { return false; } // Read the configuration file if (CiLoadConfigFilePathFromIni(path, sizeof(path))) { c->CfgRw = NewCfgRw(&root, path); } else { c->CfgRw = NewCfgRw(&root, CLIENT_CONFIG_FILE_NAME); } if (root == NULL) { return false; } ret = CiReadSettingFromCfg(c, root); CfgDeleteFolder(root); return ret; } // Write the CLIENT_CONFIG void CiWriteClientConfig(FOLDER *cc, CLIENT_CONFIG *config) { // Validate arguments if (cc == NULL || config == NULL) { return; } CfgAddBool(cc, "UseKeepConnect", config->UseKeepConnect); CfgAddStr(cc, "KeepConnectHost", config->KeepConnectHost); CfgAddInt(cc, "KeepConnectPort", config->KeepConnectPort); CfgAddInt(cc, "KeepConnectProtocol", config->KeepConnectProtocol); CfgAddBool(cc, "AllowRemoteConfig", config->AllowRemoteConfig); CfgAddInt(cc, "KeepConnectInterval", config->KeepConnectInterval); CfgAddBool(cc, "NoChangeWcmNetworkSettingOnWindows8", config->NoChangeWcmNetworkSettingOnWindows8); } // Write the client authentication data void CiWriteClientAuth(FOLDER *f, CLIENT_AUTH *a) { BUF *b; // Validate arguments if (f == NULL || a == NULL) { return; } CfgAddInt(f, "AuthType", a->AuthType); CfgAddStr(f, "Username", a->Username); switch (a->AuthType) { case CLIENT_AUTHTYPE_ANONYMOUS: break; case CLIENT_AUTHTYPE_PASSWORD: CfgAddByte(f, "HashedPassword", a->HashedPassword, SHA1_SIZE); break; case CLIENT_AUTHTYPE_PLAIN_PASSWORD: b = EncryptPassword(a->PlainPassword); CfgAddByte(f, "EncryptedPassword", b->Buf, b->Size); FreeBuf(b); break; case CLIENT_AUTHTYPE_CERT: if (a->ClientK != NULL && a->ClientX != NULL) { b = XToBuf(a->ClientX, false); CfgAddByte(f, "ClientCert", b->Buf, b->Size); FreeBuf(b); b = KToBuf(a->ClientK, false, NULL); CfgAddByte(f, "ClientKey", b->Buf, b->Size); FreeBuf(b); } break; case CLIENT_AUTHTYPE_SECURE: CfgAddStr(f, "SecurePublicCertName", a->SecurePublicCertName); CfgAddStr(f, "SecurePrivateKeyName", a->SecurePrivateKeyName); break; case CLIENT_AUTHTYPE_OPENSSLENGINE: if (a->ClientX != NULL) { b = XToBuf(a->ClientX, false); CfgAddByte(f, "ClientCert", b->Buf, b->Size); FreeBuf(b); } CfgAddStr(f, "OpensslEnginePrivateKeyName", a->OpensslEnginePrivateKeyName); CfgAddStr(f, "OpensslEngineName", a->OpensslEngineName); break; } } // Write the client option void CiWriteClientOption(FOLDER *f, CLIENT_OPTION *o) { BUF *b; // Validate arguments if (f == NULL || o == NULL) { return; } CfgAddUniStr(f, "AccountName", o->AccountName); // Append hint string to hostname if (IsEmptyStr(o->HintStr)) { // No hint CfgAddStr(f, "Hostname", o->Hostname); } else { char hostname[MAX_SIZE]; StrCpy(hostname, sizeof(hostname), o->Hostname); StrCat(hostname, sizeof(hostname), "/"); StrCat(hostname, sizeof(hostname), o->HintStr); CfgAddStr(f, "Hostname", hostname); } CfgAddInt(f, "Port", o->Port); CfgAddInt(f, "PortUDP", o->PortUDP); CfgAddInt(f, "ProxyType", o->ProxyType); CfgAddStr(f, "ProxyName", o->ProxyName); CfgAddInt(f, "ProxyPort", o->ProxyPort); CfgAddStr(f, "ProxyUsername", o->ProxyUsername); b = EncryptPassword(o->ProxyPassword); CfgAddByte(f, "ProxyPassword", b->Buf, b->Size); FreeBuf(b); CfgAddStr(f, "CustomHttpHeader", o->CustomHttpHeader); CfgAddInt(f, "NumRetry", o->NumRetry); CfgAddInt(f, "RetryInterval", o->RetryInterval); CfgAddStr(f, "HubName", o->HubName); CfgAddInt(f, "MaxConnection", o->MaxConnection); CfgAddBool(f, "UseEncrypt", o->UseEncrypt); CfgAddBool(f, "UseCompress", o->UseCompress); CfgAddBool(f, "HalfConnection", o->HalfConnection); CfgAddBool(f, "NoRoutingTracking", o->NoRoutingTracking); CfgAddStr(f, "DeviceName", o->DeviceName); CfgAddInt(f, "AdditionalConnectionInterval", o->AdditionalConnectionInterval); CfgAddBool(f, "HideStatusWindow", o->HideStatusWindow); CfgAddBool(f, "HideNicInfoWindow", o->HideNicInfoWindow); CfgAddInt(f, "ConnectionDisconnectSpan", o->ConnectionDisconnectSpan); CfgAddBool(f, "RequireMonitorMode", o->RequireMonitorMode); CfgAddBool(f, "RequireBridgeRoutingMode", o->RequireBridgeRoutingMode); CfgAddBool(f, "DisableQoS", o->DisableQoS); CfgAddBool(f, "NoUdpAcceleration", o->NoUdpAcceleration); CfgAddIp(f, "BindLocalIP", &o->BindLocalIP);// Source IP address for outgoing connection if (o->FromAdminPack) { CfgAddBool(f, "FromAdminPack", o->FromAdminPack); } if (IsZero(o->HostUniqueKey, SHA1_SIZE) == false) { BUF *b = MemToBuf(o->HostUniqueKey, SHA1_SIZE); CfgAddBuf(f, "HostUniqueKey", b); FreeBuf(b); } } // Decrypt the password char *DecryptPassword(BUF *b) { char *str; char *key = "EncryptPassword"; CRYPT *c; // Validate arguments if (b == NULL) { return CopyStr(""); } str = ZeroMalloc(b->Size + 1); c = NewCrypt(key, sizeof(key)); // NOTE by Daiyuu Nobori 2018-09-28: This is not a bug! Do not try to fix it!! Encrypt(c, str, b->Buf, b->Size); FreeCrypt(c); str[b->Size] = 0; return str; } char *DecryptPassword2(BUF *b) { char *str; char *key = "EncryptPassword2"; CRYPT *c; // Validate arguments if (b == NULL) { return CopyStr(""); } str = ZeroMalloc(b->Size + 1); c = NewCrypt(key, StrLen(key)); Encrypt(c, str, b->Buf, b->Size); FreeCrypt(c); str[b->Size] = 0; return str; } // Encrypt the password BUF *EncryptPassword(char *password) { UCHAR *tmp; UINT size; char *key = "EncryptPassword"; CRYPT *c; BUF *b; // Validate arguments if (password == NULL) { password = ""; } size = StrLen(password) + 1; tmp = ZeroMalloc(size); c = NewCrypt(key, sizeof(key)); // NOTE by Daiyuu Nobori 2018-09-28: This is not a bug! Do not try to fix it!! Encrypt(c, tmp, password, size - 1); FreeCrypt(c); b = NewBuf(); WriteBuf(b, tmp, size - 1); SeekBuf(b, 0, 0); Free(tmp); return b; } BUF *EncryptPassword2(char *password) { UCHAR *tmp; UINT size; char *key = "EncryptPassword2"; CRYPT *c; BUF *b; // Validate arguments if (password == NULL) { password = ""; } size = StrLen(password) + 1; tmp = ZeroMalloc(size); c = NewCrypt(key, StrLen(key)); Encrypt(c, tmp, password, size - 1); FreeCrypt(c); b = NewBuf(); WriteBuf(b, tmp, size - 1); SeekBuf(b, 0, 0); Free(tmp); return b; } // Write the account data void CiWriteAccountData(FOLDER *f, ACCOUNT *a) { // Validate arguments if (f == NULL || a == NULL) { return; } // Client Option CiWriteClientOption(CfgCreateFolder(f, "ClientOption"), a->ClientOption); // Client authentication data CiWriteClientAuth(CfgCreateFolder(f, "ClientAuth"), a->ClientAuth); // Startup account CfgAddBool(f, "StartupAccount", a->StartupAccount); // Server certificate check flag CfgAddBool(f, "CheckServerCert", a->CheckServerCert); // Retry on invalid server certificate flag CfgAddBool(f, "RetryOnServerCert", a->RetryOnServerCert); // Add default SSL trust store CfgAddBool(f, "AddDefaultCA", a->AddDefaultCA); // Date and time CfgAddInt64(f, "CreateDateTime", a->CreateDateTime); CfgAddInt64(f, "UpdateDateTime", a->UpdateDateTime); CfgAddInt64(f, "LastConnectDateTime", a->LastConnectDateTime); // Server certificate body if (a->ServerCert != NULL) { BUF *b = XToBuf(a->ServerCert, false); if (b != NULL) { CfgAddBuf(f, "ServerCert", b); FreeBuf(b); } } // Shortcut Key if (IsZero(a->ShortcutKey, SHA1_SIZE) == false) { char tmp[64]; BinToStr(tmp, sizeof(tmp), a->ShortcutKey, SHA1_SIZE); CfgAddStr(f, "ShortcutKey", tmp); } } // Write the account database void CiWriteAccountDatabase(CLIENT *c, FOLDER *f) { char name[MAX_SIZE]; // Validate arguments if (c == NULL || f == NULL) { return; } LockList(c->AccountList); { UINT i; for (i = 0;i < LIST_NUM(c->AccountList);i++) { ACCOUNT *a = LIST_DATA(c->AccountList, i); { Format(name, sizeof(name), "Account%u", i); Lock(a->lock); { CiWriteAccountData(CfgCreateFolder(f, name), a); } Unlock(a->lock); } } } UnlockList(c->AccountList); } // Write the CA certificate void CiWriteCACert(CLIENT *c, FOLDER *f, X *x) { BUF *b; // Validate arguments if (c == NULL || f == NULL || x == NULL) { return; } b = XToBuf(x, false); CfgAddBuf(f, "X509", b); FreeBuf(b); } // Write a VLAN void CiWriteVLan(CLIENT *c, FOLDER *f, UNIX_VLAN *v) { char tmp[MAX_SIZE]; // Validate arguments if (c == NULL || f == NULL || v == NULL) { return; } MacToStr(tmp, sizeof(tmp), v->MacAddress); CfgAddStr(f, "MacAddress", tmp); CfgAddBool(f, "Enabled", v->Enabled); } // Write a VLAN list void CiWriteVLanList(CLIENT *c, FOLDER *f) { // Validate arguments if (c == NULL || f == NULL) { return; } LockList(c->UnixVLanList); { UINT i; for (i = 0;i < LIST_NUM(c->UnixVLanList);i++) { UNIX_VLAN *v = LIST_DATA(c->UnixVLanList, i); CiWriteVLan(c, CfgCreateFolder(f, v->Name), v); } } UnlockList(c->UnixVLanList); } // Write the CA list void CiWriteCAList(CLIENT *c, FOLDER *f) { CEDAR *cedar; // Validate arguments if (c == NULL || f == NULL) { return; } cedar = c->Cedar; LockList(cedar->CaList); { UINT i; for (i = 0;i < LIST_NUM(cedar->CaList);i++) { char tmp[MAX_SIZE]; X *x = LIST_DATA(cedar->CaList, i); Format(tmp, sizeof(tmp), "Certificate%u", i); CiWriteCACert(c, CfgCreateFolder(f, tmp), x); } } UnlockList(cedar->CaList); } // Write the current settings to ROOT void CiWriteSettingToCfg(CLIENT *c, FOLDER *root) { FOLDER *cc; FOLDER *account_database; FOLDER *ca; FOLDER *vlan; FOLDER *cmsetting; FOLDER *proxy; // Validate arguments if (c == NULL || root == NULL) { return; } cmsetting = CfgCreateFolder(root, "ClientManagerSetting"); // CLIENT_CONFIG cc = CfgCreateFolder(root, "Config"); CiWriteClientConfig(cc, &c->Config); // Eraser CfgAddInt64(cc, "AutoDeleteCheckDiskFreeSpaceMin", c->Eraser->MinFreeSpace); // Account Database account_database = CfgCreateFolder(root, "AccountDatabase"); CiWriteAccountDatabase(c, account_database); // Proxy proxy = CfgCreateFolder(root, "CommonProxySetting"); if (proxy != NULL) { INTERNET_SETTING *t = &c->CommonProxySetting; BUF *pw; CfgAddInt(proxy, "ProxyType", t->ProxyType); CfgAddStr(proxy, "ProxyHostName", t->ProxyHostName); CfgAddInt(proxy, "ProxyPort", t->ProxyPort); CfgAddStr(proxy, "ProxyUsername", t->ProxyUsername); if (IsEmptyStr(t->ProxyPassword) == false) { pw = EncryptPassword(t->ProxyPassword); CfgAddBuf(proxy, "ProxyPassword", pw); FreeBuf(pw); } CfgAddStr(proxy, "CustomHttpHeader", t->CustomHttpHeader); } // CA ca = CfgCreateFolder(root, "RootCA"); CiWriteCAList(c, ca); // VLAN if (OS_IS_UNIX(GetOsInfo()->OsType) #ifdef NO_VLAN && GetOsInfo()->OsType != OSTYPE_MACOS_X #endif // NO_VLAN ) { vlan = CfgCreateFolder(root, "UnixVLan"); CiWriteVLanList(c, vlan); } // Password CfgAddByte(root, "EncryptedPassword", c->EncryptedPassword, SHA1_SIZE); CfgAddBool(root, "PasswordRemoteOnly", c->PasswordRemoteOnly); // UseSecureDeviceId CfgAddInt(root, "UseSecureDeviceId", c->UseSecureDeviceId); // DontSavePassword CfgAddBool(root, "DontSavePassword", c->DontSavePassword); // UserAgent if (c->Cedar != NULL) { CfgAddStr(root, "UserAgent", c->Cedar->HttpUserAgent); } if (cmsetting != NULL) { CM_SETTING *s = c->CmSetting; CfgAddBool(cmsetting, "EasyMode", s->EasyMode); CfgAddBool(cmsetting, "LockMode", s->LockMode); if (IsZero(s->HashedPassword, sizeof(s->HashedPassword)) == false) { CfgAddByte(cmsetting, "HashedPassword", s->HashedPassword, sizeof(s->HashedPassword)); } } } // Apply settings of Inner VPN Server void CiApplyInnerVPNServerConfig(CLIENT *c) { } // Write to the configuration file void CiSaveConfigurationFile(CLIENT *c) { FOLDER *root; // Validate arguments if (c == NULL) { return; } // Do not save the configuration file if(c->NoSaveConfig) { return; } root = CfgCreateFolder(NULL, TAG_ROOT); CiWriteSettingToCfg(c, root); SaveCfgRw(c->CfgRw, root); CfgDeleteFolder(root); } // Set the CM_SETTING bool CtSetCmSetting(CLIENT *c, CM_SETTING *s) { // Validate arguments if (c == NULL || s == NULL) { return false; } Copy(c->CmSetting, s, sizeof(CM_SETTING)); CiSaveConfigurationFile(c); return true; } // Get the CM_SETTING bool CtGetCmSetting(CLIENT *c, CM_SETTING *s) { // Validate arguments if (c == NULL || s == NULL) { return false; } Copy(s, c->CmSetting, sizeof(CM_SETTING)); return true; } // Get the client version bool CtGetClientVersion(CLIENT *c, RPC_CLIENT_VERSION *ver) { // Validate arguments if (ver == NULL) { return false; } Zero(ver, sizeof(RPC_CLIENT_VERSION)); StrCpy(ver->ClientProductName, sizeof(ver->ClientProductName), CEDAR_CLIENT_STR); StrCpy(ver->ClientVersionString, sizeof(ver->ClientVersionString), c->Cedar->VerString); StrCpy(ver->ClientBuildInfoString, sizeof(ver->ClientBuildInfoString), c->Cedar->BuildInfo); ver->ClientVerInt = c->Cedar->Version; ver->ClientBuildInt = c->Cedar->Build; #ifdef OS_WIN32 ver->ProcessId = MsGetProcessId(); ver->IsVLanNameRegulated = MsIsInfCatalogRequired(); #endif // OS_WIN32 ver->OsType = GetOsInfo()->OsType; return true; } // Creating a Client object CLIENT *CiNewClient() { CLIENT *c = ZeroMalloc(sizeof(CLIENT)); // StartCedarLog(); if (ci_active_sessions_lock == NULL) { ci_active_sessions_lock = NewLock(); ci_num_active_sessions = 0; } #ifdef OS_WIN32 if (MsIsWindows7()) { c->MsSuspendHandler = MsNewSuspendHandler(); } #endif // OS_WIN32 c->CmSetting = ZeroMalloc(sizeof(CM_SETTING)); c->SockList = NewSockList(); c->lock = NewLock(); c->lockForConnect = NewLock(); c->ref = NewRef(); c->Cedar = NewCedar(NULL, NULL); c->Cedar->Client = c; c->NotifyCancelList = NewList(NULL); Sha0(c->EncryptedPassword, "", 0); #ifdef OS_WIN32 c->GlobalPulse = MsOpenOrCreateGlobalPulse(CLIENT_GLOBAL_PULSE_NAME); #endif // OS_WIN32 if (c->GlobalPulse != NULL) { c->PulseRecvThread = NewThread(CiPulseRecvThread, c); } CiLoadIniSettings(c); // Log Settings if(c->NoSaveLog == false) { MakeDir(CLIENT_LOG_DIR_NAME); c->Logger = NewLog(CLIENT_LOG_DIR_NAME, CLIENT_LOG_PREFIX, LOG_SWITCH_DAY); } CLog(c, "L_LINE"); CLog(c, "LC_START_2", CEDAR_CLIENT_STR, c->Cedar->VerString); CLog(c, "LC_START_3", c->Cedar->BuildInfo); CLog(c, "LC_START_1"); #ifdef OS_WIN32 { // Initialize the Win32 UI wchar_t tmp[MAX_SIZE]; StrToUni(tmp, sizeof(tmp), CEDAR_CLIENT_STR); InitWinUi(tmp, _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE")); } #endif // OS_WIN32 // Initialize the settings CiInitConfiguration(c); // Raise the priority OSSetHighPriority(); CiChangeAllVLanMacAddressIfMachineChanged(c); CiChangeAllVLanMacAddressIfCleared(c); // Initialize the internal VPN server CiApplyInnerVPNServerConfig(c); return c; } // Send a global pulse void CiSendGlobalPulse(CLIENT *c) { // Validate arguments if (c == NULL) { return; } #ifdef OS_WIN32 MsSendGlobalPulse(c->GlobalPulse); #endif // OS_WIN32 } // Pulse reception thread void CiPulseRecvThread(THREAD *thread, void *param) { #ifdef OS_WIN32 CLIENT *c = (CLIENT *)param; if (c == NULL) { return; } while (true) { if (c->HaltPulseThread) { break; } MsWaitForGlobalPulse(c->GlobalPulse, INFINITE); if (c->HaltPulseThread) { break; } CiNotifyInternal(c); } #endif // OS_WIN32 } // Clean-up the client void CiCleanupClient(CLIENT *c) { // Validate arguments if (c == NULL) { return; } // Release the settings CiFreeConfiguration(c); #ifdef OS_WIN32 // Release the Win32 UI FreeWinUi(); #endif // OS_WIN32 CLog(c, "LC_END"); CLog(c, "L_LINE"); FreeEraser(c->Eraser); FreeLog(c->Logger); c->Logger = NULL; ReleaseCedar(c->Cedar); DeleteLock(c->lockForConnect); DeleteLock(c->lock); c->HaltPulseThread = true; if (c->GlobalPulse != NULL) { #ifdef OS_WIN32 MsSendGlobalPulse(c->GlobalPulse); #endif // OS_WIN32 } if (c->PulseRecvThread != NULL) { WaitThread(c->PulseRecvThread, INFINITE); ReleaseThread(c->PulseRecvThread); } if (c->GlobalPulse != NULL) { #ifdef OS_WIN32 MsCloseGlobalPulse(c->GlobalPulse); #endif // OS_WIN32 } ReleaseList(c->NotifyCancelList); FreeSockList(c->SockList); Free(c->CmSetting); #ifdef OS_WIN32 if (c->MsSuspendHandler != NULL) { MsFreeSuspendHandler(c->MsSuspendHandler); } #endif // OS_WIN32 Free(c); StopCedarLog(); if (ci_active_sessions_lock != NULL) { DeleteLock(ci_active_sessions_lock); ci_active_sessions_lock = NULL; ci_num_active_sessions = 0; } } // Increment of the number of active sessions void CiIncrementNumActiveSessions() { Lock(ci_active_sessions_lock); { ci_num_active_sessions++; } Unlock(ci_active_sessions_lock); } // Decrement of the number of active sessions void CiDecrementNumActiveSessions() { Lock(ci_active_sessions_lock); { if (ci_num_active_sessions >= 1) { ci_num_active_sessions--; } } Unlock(ci_active_sessions_lock); } // Release the client void CtReleaseClient(CLIENT *c) { // Validate arguments if (c == NULL) { return; } if (Release(c->ref) == 0) { CiCleanupClient(c); } } // Start the operation of the client program void CtStartClient() { UINT i; LIST *o; if (client != NULL) { // It is already in running return; } #ifdef OS_WIN32 RegistWindowsFirewallAll(); #endif // Creating a client client = CiNewClient(); // Start the Keep CiInitKeep(client); // Start the RPC server CiStartRpcServer(client); // Start the Saver CiInitSaver(client); // Start the startup connection o = NewListFast(NULL); LockList(client->AccountList); { for (i = 0;i < LIST_NUM(client->AccountList);i++) { ACCOUNT *a = LIST_DATA(client->AccountList, i); Lock(a->lock); { if (a->StartupAccount) { Add(o, CopyUniStr(a->ClientOption->AccountName)); } } Unlock(a->lock); } } UnlockList(client->AccountList); for (i = 0;i < LIST_NUM(o);i++) { wchar_t *s = LIST_DATA(o, i); RPC_CLIENT_CONNECT c; Zero(&c, sizeof(c)); UniStrCpy(c.AccountName, sizeof(c.AccountName), s); CtConnect(client, &c); Free(s); } ReleaseList(o); } // Stop the operation of the client program void CtStopClient() { UINT i, num; ACCOUNT **account_list; if (client == NULL) { // It is not running yet return; } // Halting flag client->Halt = true; // Disconnect all the RPC CiStopRpcServer(client); // Exit the client notification service CncExit(); // Exit the Keep CiFreeKeep(client); // Disconnect all accounts connected LockList(client->AccountList); { num = LIST_NUM(client->AccountList); account_list = ToArray(client->AccountList); } UnlockList(client->AccountList); for (i = 0;i < num;i++) { ACCOUNT *a = account_list[i]; SESSION *s = NULL; Lock(a->lock); { if (a->ClientSession != NULL) { s = a->ClientSession; AddRef(s->ref); } } Unlock(a->lock); if (s != NULL) { StopSession(s); ReleaseSession(s); Lock(a->lock); { if (a->ClientSession != NULL) { ReleaseSession(a->ClientSession); a->ClientSession = NULL; } } Unlock(a->lock); } } Free(account_list); // Stop the Saver CiFreeSaver(client); // Release the client CtReleaseClient(client); client = NULL; } // Client status indicator void CiClientStatusPrinter(SESSION *s, wchar_t *status) { #ifdef OS_WIN32 ACCOUNT *a; // Validate arguments if (s == NULL || status == NULL) { return; } a = s->Account; if (a == NULL) { return; } if (UniStrCmpi(status, L"init") == 0) { if (a->StatusWindow == NULL && s->Win32HideConnectWindow == false) { a->StatusWindow = CncStatusPrinterWindowStart(s); } } else if (UniStrCmpi(status, L"free") == 0) { if (a->StatusWindow != NULL) { CncStatusPrinterWindowStop(a->StatusWindow); a->StatusWindow = NULL; } } else { if (a->StatusWindow != NULL) { CncStatusPrinterWindowPrint(a->StatusWindow, status); } } #else // OS_WIN32 UniPrint(L"Status: %s\n", status); #endif // OS_WIN32 }