From 9970d6f657aa4abc08bd1719083394af791c0e25 Mon Sep 17 00:00:00 2001 From: Davide Beatrici Date: Sat, 6 Oct 2018 22:41:35 +0200 Subject: [PATCH 1/3] Mayaqua/Memory: move and adapt entry list functions from Cedar/Proto_OpenVPN --- src/Cedar/Proto_OpenVPN.c | 88 ++++++--------------------------------- src/Cedar/Proto_OpenVPN.h | 3 -- src/Mayaqua/Memory.c | 75 +++++++++++++++++++++++++++++++++ src/Mayaqua/Memory.h | 5 +++ 4 files changed, 92 insertions(+), 79 deletions(-) diff --git a/src/Cedar/Proto_OpenVPN.c b/src/Cedar/Proto_OpenVPN.c index 34f4c2c2..e3c0f32b 100644 --- a/src/Cedar/Proto_OpenVPN.c +++ b/src/Cedar/Proto_OpenVPN.c @@ -690,19 +690,19 @@ void OvsBeginIPCAsyncConnectionIfEmpty(OPENVPN_SERVER *s, OPENVPN_SESSION *se, O // if the option --push-peer-info is enabled. // It also sends all of the client's environment // variables whose names start with "UV_". - pi = OvsParseData(c->ClientKey.PeerInfo, OPENVPN_DATA_PEERINFO); + pi = NewEntryList(c->ClientKey.PeerInfo, "\n", "=\t"); // Check presence of custom hostname - if (OvsHasEntry(pi, "UV_HOSTNAME")) + if (EntryListHasKey(pi, "UV_HOSTNAME")) { - StrCpy(p.ClientHostname, sizeof(p.ClientHostname), IniStrValue(pi, "UV_HOSTNAME")); + StrCpy(p.ClientHostname, sizeof(p.ClientHostname), EntryListStrValue(pi, "UV_HOSTNAME")); } else // Use the default gateway's MAC address { - StrCpy(p.ClientHostname, sizeof(p.ClientHostname), IniStrValue(pi, "IV_HWADDR")); + StrCpy(p.ClientHostname, sizeof(p.ClientHostname), EntryListStrValue(pi, "IV_HWADDR")); } - OvsFreeList(pi); + FreeEntryList(pi); if (se->Mode == OPENVPN_MODE_L3) { @@ -814,13 +814,13 @@ void OvsSetupSessionParameters(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_C StrCpy(opt_str, sizeof(opt_str), s->Cedar->OpenVPNDefaultClientOption); } - o = OvsParseData(opt_str, OPENVPN_DATA_OPTIONS); + o = NewEntryList(opt_str, ",", " \t"); if (se->Mode == OPENVPN_MODE_UNKNOWN) { UINT mtu; // Layer - if (StrCmpi(IniStrValue(o, "dev-type"), "tun") == 0) + if (StrCmpi(EntryListStrValue(o, "dev-type"), "tun") == 0) { // L3 se->Mode = OPENVPN_MODE_L3; @@ -832,7 +832,7 @@ void OvsSetupSessionParameters(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_C } // Link MTU - mtu = IniIntValue(o, "link-mtu"); + mtu = EntryListIntValue(o, "link-mtu"); if (mtu == 0) { mtu = OPENVPN_MTU_LINK; @@ -840,7 +840,7 @@ void OvsSetupSessionParameters(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_C se->LinkMtu = mtu; // Tun MTU - mtu = IniIntValue(o, "tun-mtu"); + mtu = EntryListIntValue(o, "tun-mtu"); if (mtu == 0) { mtu = OPENVPN_MTU_TUN; @@ -876,12 +876,12 @@ void OvsSetupSessionParameters(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_C } // Encryption algorithm - cipher_name = IniStrValue(o, "cipher"); + cipher_name = EntryListStrValue(o, "cipher"); c->CipherEncrypt = OvsGetCipher(cipher_name); c->CipherDecrypt = OvsGetCipher(cipher_name); // Hash algorithm - c->MdSend = OvsGetMd(IniStrValue(o, "auth")); + c->MdSend = OvsGetMd(EntryListStrValue(o, "auth")); c->MdRecv = NewMd(c->MdSend->Name); // Random number generation @@ -915,7 +915,7 @@ void OvsSetupSessionParameters(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_C SetMdKey(c->MdRecv, c->ExpansionKey + 64, c->MdRecv->Size); SetMdKey(c->MdSend, c->ExpansionKey + 192, c->MdSend->Size); - OvsFreeList(o); + FreeEntryList(o); // We pass the cipher name sent from the OpenVPN client, unless it's a different cipher, to prevent a message such as: // WARNING: 'cipher' is used inconsistently, local='cipher AES-128-GCM', remote='cipher aes-128-gcm' @@ -982,70 +982,6 @@ MD *OvsGetMd(char *name) return m; } -// Parse data string -LIST *OvsParseData(char *str, int type) -{ - LIST *o = NewListFast(NULL); - TOKEN_LIST *t; - - t = ParseTokenWithoutNullStr(str, type == OPENVPN_DATA_OPTIONS ? "," : "\n"); - if (t != NULL) - { - UINT i; - - for (i = 0;i < t->NumTokens;i++) - { - char key[MAX_SIZE]; - char value[MAX_SIZE]; - char *line = t->Token[i]; - Trim(line); - - if (GetKeyAndValue(line, key, sizeof(key), value, sizeof(value), type == OPENVPN_DATA_OPTIONS ? " \t" : "=\t")) - { - INI_ENTRY *e = ZeroMalloc(sizeof(INI_ENTRY)); - - e->Key = CopyStr(key); - e->Value = CopyStr(value); - - Add(o, e); - } - } - - FreeToken(t); - } - - return o; -} - -// Release the option list -void OvsFreeList(LIST *o) -{ - // Validate arguments - if (o == NULL) - { - return; - } - - FreeIni(o); -} - -// Confirm whether there is specified option key string -bool OvsHasEntry(LIST *o, char *key) -{ - // Validate arguments - if (o == NULL || key == NULL) - { - return false; - } - - if (GetIniEntry(o, key) != NULL) - { - return true; - } - - return false; -} - // Build the data from KEY_METHOD2 BUF *OvsBuildKeyMethod2(OPENVPN_KEY_METHOD_2 *d) { diff --git a/src/Cedar/Proto_OpenVPN.h b/src/Cedar/Proto_OpenVPN.h index 811d0cf7..8a57e244 100644 --- a/src/Cedar/Proto_OpenVPN.h +++ b/src/Cedar/Proto_OpenVPN.h @@ -359,9 +359,6 @@ void OvsSetupSessionParameters(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_C BUF *OvsBuildKeyMethod2(OPENVPN_KEY_METHOD_2 *d); void OvsWriteStringToBuf(BUF *b, char *str, UINT max_size); -LIST *OvsParseData(char *str, int type); -void OvsFreeList(LIST *o); -bool OvsHasEntry(LIST *o, char *key); UINT OvsPeekStringFromFifo(FIFO *f, char *str, UINT str_size); void OvsBeginIPCAsyncConnectionIfEmpty(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c); UINT OvsCalcTcpMss(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c); diff --git a/src/Mayaqua/Memory.c b/src/Mayaqua/Memory.c index f208400b..41694735 100644 --- a/src/Mayaqua/Memory.c +++ b/src/Mayaqua/Memory.c @@ -2155,6 +2155,81 @@ LIST *NewListEx2(COMPARE *cmp, bool fast, bool fast_malloc) return o; } +// Parses a string by identifying its parts using the specified separators +LIST *NewEntryList(char *src, char *key_separator, char *value_separator) +{ + LIST *o = NewListFast(NULL); + TOKEN_LIST *t; + + t = ParseTokenWithoutNullStr(src, key_separator); + if (t != NULL) + { + UINT i; + + for (i = 0; i < t->NumTokens; i++) + { + char key[MAX_SIZE]; + char value[MAX_SIZE]; + char *line = t->Token[i]; + Trim(line); + + if (GetKeyAndValue(line, key, sizeof(key), value, sizeof(value), value_separator)) + { + INI_ENTRY *e = ZeroMalloc(sizeof(INI_ENTRY)); + + e->Key = CopyStr(key); + e->Value = CopyStr(value); + + Add(o, e); + } + } + + FreeToken(t); + } + + return o; +} + +// Checks whether the list contains the specified entry +bool EntryListHasKey(LIST *o, char *key) +{ + // Validate arguments + if (o == NULL || key == NULL) + { + return false; + } + + if (GetIniEntry(o, key) != NULL) + { + return true; + } + + return false; +} + +// Gets the value of the specified key from the entry list +char *EntryListStrValue(LIST *o, char *key) +{ + return IniStrValue(o, key); +} + +UINT EntryListIntValue(LIST *o, char *key) +{ + return IniIntValue(o, key); +} + +// Release the entry list +void FreeEntryList(LIST *o) +{ + // Validate arguments + if (o == NULL) + { + return; + } + + FreeIni(o); +} + // Read all data from FIFO BUF *ReadFifoAll(FIFO *f) { diff --git a/src/Mayaqua/Memory.h b/src/Mayaqua/Memory.h index 11f9fa2e..5ba61f8b 100644 --- a/src/Mayaqua/Memory.h +++ b/src/Mayaqua/Memory.h @@ -380,6 +380,11 @@ LIST *NewListFast(COMPARE *cmp); LIST *NewListEx(COMPARE *cmp, bool fast); LIST *NewListEx2(COMPARE *cmp, bool fast, bool fast_malloc); LIST *NewListSingle(void *p); +LIST *NewEntryList(char *src, char *key_separator, char *value_separator); +bool EntryListHasKey(LIST *o, char *key); +char *EntryListStrValue(LIST *o, char *key); +UINT EntryListIntValue(LIST *o, char *key); +void FreeEntryList(LIST *o); LIST *CloneList(LIST *o); void CopyToArray(LIST *o, void *p); void *ToArray(LIST *o); From 335e0503c95d1036717380fad2a408f2f95a0c9f Mon Sep 17 00:00:00 2001 From: Davide Beatrici Date: Sat, 6 Oct 2018 22:42:29 +0200 Subject: [PATCH 2/3] Mayaqua/Str: add TrimQuotes() function to remove quotes from a string --- src/Mayaqua/Str.c | 27 +++++++++++++++++++++++++++ src/Mayaqua/Str.h | 1 + 2 files changed, 28 insertions(+) diff --git a/src/Mayaqua/Str.c b/src/Mayaqua/Str.c index 7a1c79c0..95cc515a 100644 --- a/src/Mayaqua/Str.c +++ b/src/Mayaqua/Str.c @@ -2412,6 +2412,33 @@ void TrimCrlf(char *str) } } +// Remove quotes at the beginning and at the end of the string +void TrimQuotes(char *str) +{ + UINT len = 0; + // Validate arguments + if (str == NULL) + { + return; + } + + len = StrLen(str); + if (len == 0) + { + return; + } + + if (str[len - 1] == '\"') + { + str[len - 1] = 0; + } + + if (str[0] == '\"') + { + Move(str, str + 1, len); + } +} + // Remove white spaces of the both side of the string void Trim(char *str) { diff --git a/src/Mayaqua/Str.h b/src/Mayaqua/Str.h index 7a554706..cb8c1e06 100644 --- a/src/Mayaqua/Str.h +++ b/src/Mayaqua/Str.h @@ -155,6 +155,7 @@ bool ToBool(char *str); int ToInti(char *str); void ToStr(char *str, UINT i); void TrimCrlf(char *str); +void TrimQuotes(char *str); void Trim(char *str); void TrimRight(char *str); void TrimLeft(char *str); From afe994f252986b1e601bdd73c3d542e5e3331f6c Mon Sep 17 00:00:00 2001 From: Davide Beatrici Date: Sun, 7 Oct 2018 01:38:02 +0200 Subject: [PATCH 3/3] Mayaqua/OS: improve UnixGetOsInfo() so that it retrieves info on recent Linux/BSD systems --- src/Cedar/Proto_OpenVPN.h | 4 -- src/Mayaqua/Unix.c | 98 +++++++++++++++++++++------------------ 2 files changed, 54 insertions(+), 48 deletions(-) diff --git a/src/Cedar/Proto_OpenVPN.h b/src/Cedar/Proto_OpenVPN.h index 8a57e244..0415b44d 100644 --- a/src/Cedar/Proto_OpenVPN.h +++ b/src/Cedar/Proto_OpenVPN.h @@ -184,10 +184,6 @@ #define OPENVPN_MODE_L2 1 // TAP (Ethernet) #define OPENVPN_MODE_L3 2 // TUN (IP) -// Data -#define OPENVPN_DATA_OPTIONS 0 -#define OPENVPN_DATA_PEERINFO 1 - //// Type diff --git a/src/Mayaqua/Unix.c b/src/Mayaqua/Unix.c index 4897c422..7ec8b234 100755 --- a/src/Mayaqua/Unix.c +++ b/src/Mayaqua/Unix.c @@ -125,6 +125,7 @@ #include #include #include +#include #include #ifdef UNIX_MACOS @@ -1057,6 +1058,8 @@ void UnixAlert(char *msg, char *caption) // Get the information of the current OS void UnixGetOsInfo(OS_INFO *info) { + struct utsname unix_info; + // Validate arguments if (info == NULL) { @@ -1079,68 +1082,75 @@ void UnixGetOsInfo(OS_INFO *info) info->OsType = OSTYPE_UNIX_UNKNOWN; #endif - info->OsServicePack = 0; + info->OsSystemName = CopyStr(OsTypeToStr(info->OsType)); + info->KernelName = CopyStr("UNIX"); - if (info->OsType != OSTYPE_LINUX) + if (uname(&unix_info) > -1) { - info->OsSystemName = CopyStr("UNIX"); - info->OsProductName = CopyStr("UNIX"); + info->OsProductName = CopyStr(unix_info.sysname); + info->OsVersion = CopyStr(unix_info.release); + info->KernelVersion = CopyStr(unix_info.version); } else { - info->OsSystemName = CopyStr("Linux"); - info->OsProductName = CopyStr("Linux"); - } + Debug("UnixGetOsInfo(): uname() failed with error: %s\n", strerror(errno)); - if (info->OsType == OSTYPE_LINUX) + info->OsProductName = CopyStr(OsTypeToStr(info->OsType)); + info->OsVersion = CopyStr("Unknown"); + info->KernelVersion = CopyStr("Unknown"); + } +#ifdef UNIX_LINUX { - // Get the distribution name on Linux - BUF *b; - b = ReadDump("/etc/redhat-release"); - if (b != NULL) + BUF *buffer = ReadDump("/etc/os-release"); + if (buffer == NULL) { - info->OsVersion = CfgReadNextLine(b); - info->OsVendorName = CopyStr("Red Hat, Inc."); - FreeBuf(b); + buffer = ReadDump("/usr/lib/os-release"); } - else + + if (buffer != NULL) { - b = ReadDump("/etc/turbolinux-release"); - if (b != NULL) + LIST *values = NewEntryList(buffer->Buf, "\n", "="); + + FreeBuf(buffer); + + if (EntryListHasKey(values, "NAME")) { - info->OsVersion = CfgReadNextLine(b); - info->OsVendorName = CopyStr("Turbolinux, Inc."); - FreeBuf(b); + char *str = EntryListStrValue(values, "NAME"); + TrimQuotes(str); + Free(info->OsProductName); + info->OsProductName = CopyStr(str); + } + + if (EntryListHasKey(values, "HOME_URL")) + { + char *str = EntryListStrValue(values, "HOME_URL"); + TrimQuotes(str); + info->OsVendorName = CopyStr(str); + } + + if (EntryListHasKey(values, "VERSION")) + { + char *str = EntryListStrValue(values, "VERSION"); + TrimQuotes(str); + Free(info->OsVersion); + info->OsVersion = CopyStr(str); } else { - info->OsVersion = CopyStr("Unknown Linux Version"); - info->OsVendorName = CopyStr("Unknown Vendor"); + // Debian testing/sid doesn't provide the version in /etc/os-release + buffer = ReadDump("/etc/debian_version"); + if (buffer != NULL) + { + Free(info->OsVersion); + info->OsVersion = CfgReadNextLine(buffer); + FreeBuf(buffer); + } } - } - info->KernelName = CopyStr("Linux Kernel"); - - b = ReadDump("/proc/sys/kernel/osrelease"); - if (b != NULL) - { - info->KernelVersion = CfgReadNextLine(b); - FreeBuf(b); - } - else - { - info->KernelVersion = CopyStr("Unknown Version"); + FreeEntryList(values); } } - else - { - // In other cases - Free(info->OsProductName); - info->OsProductName = CopyStr(OsTypeToStr(info->OsType)); - info->OsVersion = CopyStr("Unknown Version"); - info->KernelName = CopyStr(OsTypeToStr(info->OsType)); - info->KernelVersion = CopyStr("Unknown Version"); - } +#endif } // Examine whether the current OS is supported by the PacketiX VPN Kernel