/* Copyright 2006 - 2018 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #ifndef __APPLE__ #if defined(WIN32) && !defined(_WIN32_WCE) && !defined(_MINCORE) #define _CRTDBG_MAP_ALLOC #include #endif #if defined(WINSOCK2) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #include #elif defined(WINSOCK1) #include #include #elif defined(_POSIX) #include #include #include #include #include #include #include #include #include #include #ifndef _FREEBSD #include #endif #define inaddrr(x) (*(struct in_addr *) &ifr->x[sizeof sa.sin_port]) #define IFRSIZE ((int)(size * sizeof (struct ifreq))) #endif #include #include #include #include "../microstack/ILibParsers.h" #include "../microstack/ILibCrypto.h" #include "meshinfo.h" #ifdef WINSOCK2 // This is the Windows implementation of a method that gets information about local interfaces int info_GetLocalInterfaces(char* data, int maxdata) { #ifdef _MINCORE return 0; #else IP_ADAPTER_INFO *pAdapterInfo; IP_ADAPTER_ADDRESSES *pAdapterAddresses; PIP_ADAPTER_INFO pAdapter; PIP_ADAPTER_ADDRESSES pAdapterAddr; ULONG ulOutBufLen = 0; DWORD dwRetVal; unsigned int j; int adapterCount = 0; unsigned long palen; unsigned char pa[16]; int ptr = 0; size_t templen; char temp[1024]; IPAddr ip1; IPAddr ip2; // Lets see how much memory we need to get the list of local interfaces pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO)); if (pAdapterInfo == NULL) return 0; ulOutBufLen = sizeof(IP_ADAPTER_INFO); if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) != ERROR_SUCCESS) { free(pAdapterInfo); if (ulOutBufLen == 0) return 0; pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen); } // Get the list of all local interfaces if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) != ERROR_SUCCESS || ulOutBufLen == 0) { free(pAdapterInfo); return 0; } // Count how many interfaces are present pAdapter = pAdapterInfo; while (pAdapter) { adapterCount++; pAdapter = pAdapter->Next; } // Lets see how much memory we need to get the list of local adapters pAdapterAddresses = (IP_ADAPTER_ADDRESSES *)malloc(sizeof(IP_ADAPTER_ADDRESSES)); if (pAdapterAddresses == NULL) { free(pAdapterInfo); return 0; } ulOutBufLen = sizeof(IP_ADAPTER_ADDRESSES); if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_GATEWAYS | GAA_FLAG_INCLUDE_PREFIX, NULL, pAdapterAddresses, &ulOutBufLen) != ERROR_SUCCESS) { free(pAdapterAddresses); if (ulOutBufLen == 0) return 0; pAdapterAddresses = (IP_ADAPTER_ADDRESSES *)malloc(ulOutBufLen); } // Get the list of all local interfaces if ((dwRetVal = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_GATEWAYS | GAA_FLAG_INCLUDE_PREFIX, NULL, pAdapterAddresses, &ulOutBufLen)) != ERROR_SUCCESS || ulOutBufLen == 0) { free(pAdapterInfo); free(pAdapterAddresses); return 0; } j = 0; pAdapter = pAdapterInfo; while (pAdapter) { // Find the corresponding adapter for this interface pAdapterAddr = pAdapterAddresses; while (pAdapterAddr != NULL && pAdapterAddr->IfIndex != pAdapter->Index) { pAdapterAddr = pAdapterAddr->Next; } if (pAdapterAddr == NULL) { free(pAdapterInfo); free(pAdapterAddresses); return 0; } if (j > 0) { ptr += snprintf(data + ptr, maxdata - ptr, ","); } ptr += snprintf(data + ptr, maxdata - ptr, "{"); // Interface type ptr += snprintf(data + ptr, maxdata - ptr, "\"type\":%d", pAdapter->Type); // Interface name if (wcslen(pAdapterAddr->FriendlyName) > 0) { wcstombs_s(&templen, temp, 1023, pAdapterAddr->FriendlyName, wcslen(pAdapterAddr->FriendlyName)); ptr += snprintf(data + ptr, maxdata - ptr, ",\"name\":\"%s\"", temp); } // Interface description if (wcslen(pAdapterAddr->Description) > 0) { wcstombs_s(&templen, temp, 1023, pAdapterAddr->Description, wcslen(pAdapterAddr->Description)); ptr += snprintf(data + ptr, maxdata - ptr, ",\"desc\":\"%s\"", temp); } // Interface MAC address if (pAdapter->AddressLength == 6) { ptr += snprintf(data + ptr, maxdata - ptr, ",\"mac\":\"%02x%02x%02x%02x%02x%02x\"", pAdapter->Address[0], pAdapter->Address[1], pAdapter->Address[2], pAdapter->Address[3], pAdapter->Address[4], pAdapter->Address[5]); } // Interface DNS suffix if (wcslen(pAdapterAddr->DnsSuffix) > 0) { wcstombs_s(&templen, temp, 1023, pAdapterAddr->DnsSuffix, wcslen(pAdapterAddr->DnsSuffix)); ptr += snprintf(data + ptr, maxdata - ptr, ",\"dnssuffix\":\"%s\"", temp); } // IPv4 address and subnet mask ptr += snprintf(data + ptr, maxdata - ptr, ",\"v4addr\":\"%s\"", pAdapter->IpAddressList.IpAddress.String); ptr += snprintf(data + ptr, maxdata - ptr, ",\"v4mask\":\"%s\"", pAdapter->IpAddressList.IpMask.String); ptr += snprintf(data + ptr, maxdata - ptr, ",\"v4gateway\":\"%s\"", pAdapter->GatewayList.IpAddress.String); // Get the gateway MAC address ILibInet_pton(AF_INET, pAdapter->IpAddressList.IpAddress.String, &ip1); ILibInet_pton(AF_INET, pAdapter->GatewayList.IpAddress.String, &ip2); SendARP(ip2, ip1, pa, &palen); if (palen == 6) { ptr += snprintf(data + ptr, maxdata - ptr, ",\"gatewaymac\":\"%02x%02x%02x%02x%02x%02x\"", pa[0], pa[1], pa[2], pa[3], pa[4], pa[5]); } ptr += snprintf(data + ptr, maxdata - ptr, "}"); j++; pAdapter = pAdapter->Next; } // Free the local interface memory free(pAdapterInfo); free(pAdapterAddresses); return ptr; #endif } #endif #ifdef _POSIX // This method reads a stream where the length of the file can't be determined. Useful in POSIX only int __fastcall utilx_readfile2(char* filename, char** data) { FILE * pFile; int count = 0; int len = 0; *data = NULL; if (filename == NULL) return 0; pFile = fopen(filename, "rb"); if (pFile != NULL) { *data = malloc(1024); if (*data == NULL) { fclose(pFile); return 0; } do { len = fread((*data) + count, 1, 1023, pFile); count += len; if (len == 1023) { if ((*data = realloc(*data, count + 1024)) == NULL) { ILIBCRITICALEXIT(254); } } } while (len == 100); (*data)[count] = 0; fclose(pFile); } return count; } // TODO: Add support for IPv6, and check that it's on the correct interface int info_GetHwAddress(char* ipaddr, int ipaddrlen, char** hwaddr) { char* arpcache = NULL; int len, r = 0; char* ptr = NULL; char substr[32]; *hwaddr = NULL; if (ipaddrlen >= 30 || (ipaddrlen == 7 && memcmp(ipaddr, "0.0.0.0", 7) == 0)) return 0; len = utilx_readfile2("/proc/net/arp", &arpcache); if (len == 0) return 0; substr[0] = '\n'; memcpy(substr + 1, ipaddr, ipaddrlen); substr[ipaddrlen + 1] = ' '; substr[ipaddrlen + 2] = 0; ptr = strstr(arpcache, substr); if ((ptr != NULL) && (ptr + 61 < arpcache + len) && (ptr[44] == ':') && (ptr[47] == ':') && (ptr[56] == ':')) { if ((*hwaddr = (char*)malloc(6)) == NULL) ILIBCRITICALEXIT(254); for (; r < 6; r++) { (*hwaddr)[r] = util_hexToint(ptr + 42 + (r * 3), 2); } } free(arpcache); return r; } // The Linux equal of Windows SendARP int SendARP(char* DestIP, char* SrcIP, void* pMacAddr, int* PhyAddrLen) { char tmp[50]; char* ptr = NULL; ILibInet_ntop(AF_INET, DestIP, tmp, 50); if (*PhyAddrLen < 6) return -1; *PhyAddrLen = info_GetHwAddress(tmp, strlen(tmp), &ptr); if (ptr != NULL) { memcpy(pMacAddr, ptr, 6); free(ptr); return 0; } return -1; } // TODO: See if we can do this for each interface, right now interface is ignored int info_GetDefaultFqdn(char* ifname, char** fqdn) { char* resolv; int len, r = 0; struct parser_result* parse; struct parser_result_field* p; struct parser_result* parse2; struct parser_result_field* p2; *fqdn = NULL; len = utilx_readfile2("/etc/resolv.conf", &resolv); if (len == 0) return 0; parse = ILibParseString(resolv, 0, len, "\n", 1); p = parse->FirstResult; while (p != NULL) { parse2 = ILibParseString(p->data, 0, p->datalength, " ", 1); p2 = parse2->FirstResult; if (p2->datalength == 6 && memcmp(p2->data, "domain", 6) == 0) { // We found the system's default FQDN r = p2->NextResult->datalength; *fqdn = malloc(r + 1); memcpy(*fqdn, p2->NextResult->data, r); (*fqdn)[r] = 0; ILibDestructParserResults(parse2); break; } ILibDestructParserResults(parse2); p = p->NextResult; // Skip to next line } ILibDestructParserResults(parse); free(resolv); return r; } // TODO: Add IPv6 support int info_GetDefaultGateway(char* ifname, char** gateway) { char* route; char* temp; int len, r = 0, i; int ifnamelen = strlen(ifname); struct parser_result* parse; struct parser_result_field* p; struct parser_result* parse2; struct parser_result_field* p2; *gateway = NULL; len = utilx_readfile2("/proc/net/route", &route); if (len == 0) return 0; parse = ILibParseString(route, 0, len, "\n", 1); p = parse->FirstResult; p = p->NextResult; // Skip the first line while (p != NULL) { parse2 = ILibParseString(p->data, 0, p->datalength, "\t", 1); p2 = parse2->FirstResult; if (ifnamelen == p2->datalength && memcmp(p2->data, ifname, ifnamelen) == 0) { if (p2->NextResult->datalength == 8 && memcmp(p2->NextResult->data, "00000000", 8) == 0) { // We found the default gateway for this interface r = p2->NextResult->NextResult->datalength / 2; *gateway = malloc(r); temp = p2->NextResult->NextResult->data; for (i = 0; i < r; i++) { (*gateway)[r - (i + 1)] = util_hexToint(temp + (i * 2), 2); } ILibDestructParserResults(parse2); break; } } ILibDestructParserResults(parse2); p = p->NextResult; // Skip to next line } ILibDestructParserResults(parse); free(route); return r; } // This is the POSIX implementation of a method that gets information about local interfaces int info_GetLocalInterfaces(char* data, int maxdata) { #if defined NACL || defined(_FREEBSD) return 0; #else int ptr = 0; int sockfd, size = 1, j; int adapterCount = 0; struct ifreq *ifr; struct ifconf ifc; char temp[1024]; char* gateway = NULL; // Fetch the list of local interfaces if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) return 0; ifc.ifc_len = IFRSIZE; ifc.ifc_req = NULL; do { ++size; // realloc buffer size until no overflow occurs if ((ifc.ifc_req = realloc(ifc.ifc_req, IFRSIZE)) == NULL) return 0; ifc.ifc_len = IFRSIZE; if (ioctl(sockfd, SIOCGIFCONF, &ifc) != 0) return 0; } while (IFRSIZE <= ifc.ifc_len); ifr = ifc.ifc_req; for (; (char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len; ++ifr) { if (ifr->ifr_addr.sa_data == (ifr + 1)->ifr_addr.sa_data) continue; // Duplicate if (ioctl(sockfd, SIOCGIFFLAGS, ifr)) continue; // Failed if (memcmp(ifr->ifr_name, "lo", 3) == 0) continue; // Loopback if (adapterCount > 0) { ptr += snprintf(data + ptr, maxdata - ptr, ","); } ptr += snprintf(data + ptr, maxdata - ptr, "{"); // Get the name of the interface ptr += snprintf(data + ptr, maxdata - ptr, "\"name\":\"%s\"", ifr->ifr_name); // Get the FQDN (DNS Suffix) j = info_GetDefaultFqdn(ifr->ifr_name, &gateway); if (j > 0) { ptr += snprintf(data + ptr, maxdata - ptr, ",\"dnssuffix\":\"%s\"", gateway); } if (gateway != NULL) { free(gateway); gateway = NULL; } // Get the Default Gateway IP address j = info_GetDefaultGateway(ifr->ifr_name, &gateway); if (j == 4) { ILibInet_ntop(AF_INET, gateway, temp, 1024); ptr += snprintf(data + ptr, maxdata - ptr, ",\"v4gateway\":\"%s\"", temp); } if (gateway != NULL) { free(gateway); gateway = NULL; } // Get the Default Gateway MAC address j = info_GetHwAddress(temp, strlen(temp), &gateway); if (j == 6) { ptr += snprintf(data + ptr, maxdata - ptr, ",\"gatewaymac\":\"%02x%02x%02x%02x%02x%02x\"", (unsigned char)gateway[0], (unsigned char)gateway[1], (unsigned char)gateway[2], (unsigned char)gateway[3], (unsigned char)gateway[4], (unsigned char)gateway[5]); } if (gateway != NULL) free(gateway); // Attempt to figure out the interface type j = 0; if (strlen(ifr->ifr_name) > 3 && memcmp(ifr->ifr_name, "eth", 3) == 0) { j = 6; } //if (strlen(ifr->ifr_name) > 2 && memcmp(ifr->ifr_name, "wl", 2) == 0) { j = 6; } // TODO: Wireless if (j > 0) { ptr += snprintf(data + ptr, maxdata - ptr, ",\"type\":\"%d\"", j); } // Get the hardware MAC address if (ioctl(sockfd, SIOCGIFHWADDR, ifr) == 0) { if (ifr->ifr_hwaddr.sa_family == 1) { ptr += snprintf(data + ptr, maxdata - ptr, ",\"mac\":\"%02x%02x%02x%02x%02x%02x\"", (unsigned char)ifr->ifr_hwaddr.sa_data[0], (unsigned char)ifr->ifr_hwaddr.sa_data[1], (unsigned char)ifr->ifr_hwaddr.sa_data[2], (unsigned char)ifr->ifr_hwaddr.sa_data[3], (unsigned char)ifr->ifr_hwaddr.sa_data[4], (unsigned char)ifr->ifr_hwaddr.sa_data[5]); } } // Get the IP address if (ioctl(sockfd, SIOCGIFADDR, ifr) == 0) { ptr += snprintf(data + ptr, maxdata - ptr, ",\"v4addr\":\"%s\"", inet_ntoa(((struct sockaddr_in*)(&(ifr->ifr_addr)))->sin_addr)); } // Get the subnet mask if (ioctl(sockfd, SIOCGIFNETMASK, ifr) == 0) { ptr += snprintf(data + ptr, maxdata - ptr, ",\"v4mask\":\"%s\"", inet_ntoa(((struct sockaddr_in*)(&(ifr->ifr_addr)))->sin_addr)); } ptr += snprintf(data + ptr, maxdata - ptr, "}"); adapterCount++; } free(ifc.ifc_req); close(sockfd); return ptr; #endif } #endif // Returns a JSON text with system information int MeshInfo_GetSystemInformation(char** data) { int ptr = 0; // Setup the response if ((*data = (char*)malloc(65536)) == NULL) { ILIBCRITICALEXIT(254); } ptr += snprintf(*data + ptr, 65536 - ptr, "{\"netif\":["); ptr += info_GetLocalInterfaces(*data + ptr, 65536 - ptr); ptr += snprintf(*data + ptr, 65536 - ptr, "]}"); (*data)[ptr] = 0; if ((*data = realloc(*data, ptr + 1)) == NULL) { ILIBCRITICALEXIT(254); } return ptr; } #ifdef WIN32 #if defined(_LINKVM) DWORD WINAPI kvm_ctrlaltdel(LPVOID Param); #endif int MeshInfo_PowerState(enum AgentPowerStateActions flg, int force) { #ifdef _MINCORE if (flg == 0 || flg > 5) return 0; // NOP switch (flg) { case POWERSTATE_SHUTDOWN: // SHUTDOWN InitiateSystemShutdownEx(NULL, NULL, 30, TRUE, FALSE, SHTDN_REASON_MINOR_OTHER); break; case POWERSTATE_REBOOT: // REBOOT InitiateSystemShutdownEx(NULL, NULL, 30, TRUE, TRUE, SHTDN_REASON_MINOR_OTHER); break; } return 1; #else TOKEN_PRIVILEGES tp; BOOL fResult = 0; HANDLE ht; if (flg == POWERSTATE_NOP) return 0; // NOP if (flg == POWERSTATE_DISPLAYON) { SetThreadExecutionState(ES_DISPLAY_REQUIRED); SetThreadExecutionState(ES_USER_PRESENT); return 1; } // Turn on display if (flg == POWERSTATE_KEEPAWAKE) { SetThreadExecutionState(ES_SYSTEM_REQUIRED); return 1; } // Keep system awake if (flg == POWERSTATE_BEEP) { MessageBeep(0xFFFFFFFF); return 1; } if (flg == POWERSTATE_CTRLALTDEL) { #if defined(_LINKVM) ht = CreateThread(NULL, 0, kvm_ctrlaltdel, 0, 0, 0); if (ht != NULL) CloseHandle(ht); return 1; #else return 0; #endif } // Attempt to exit if (flg > POWERSTATE_HIBERNATE) return 0; // NOP if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &ht)) return 0; LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tp.Privileges[0].Luid); tp.PrivilegeCount = 1; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; AdjustTokenPrivileges(ht, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0); if (GetLastError() != ERROR_SUCCESS) { CloseHandle(ht); return 0; } switch (flg) { case POWERSTATE_LOGOFF: // LOGOFF if (force) fResult = ExitWindowsEx(EWX_LOGOFF | EWX_FORCE, SHTDN_REASON_FLAG_PLANNED); else fResult = ExitWindowsEx(EWX_LOGOFF, SHTDN_REASON_FLAG_PLANNED); break; case POWERSTATE_SHUTDOWN: // SHUTDOWN fResult = InitiateSystemShutdown(NULL, NULL, 30, TRUE, FALSE); break; case POWERSTATE_REBOOT: // REBOOT fResult = InitiateSystemShutdown(NULL, NULL, 30, TRUE, TRUE); break; case POWERSTATE_SLEEP: // SLEEP fResult = SetSystemPowerState(TRUE, force); break; case POWERSTATE_HIBERNATE: // HIBERNATE fResult = SetSystemPowerState(FALSE, force); break; } if (!fResult) { CloseHandle(ht); return 0; } tp.Privileges[0].Attributes = 0; AdjustTokenPrivileges(ht, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0); CloseHandle(ht); return 1; #endif } #elif defined(_VX_CPU) || defined(_FREEBSD) // If VxWorks, we still need to implement this. int MeshInfo_PowerState(enum AgentPowerStateActions flg, int force) { // TODO return 0; } #else int MeshInfo_PowerState(enum AgentPowerStateActions flg, int force) { switch (flg) { case POWERSTATE_NOP: case POWERSTATE_DISPLAYON: case POWERSTATE_KEEPAWAKE: case POWERSTATE_BEEP: case POWERSTATE_CTRLALTDEL: // NO OP break; case POWERSTATE_LOGOFF: // LOGOFF break; case POWERSTATE_SHUTDOWN: // SHUTDOWN #if defined(_ANDROID) reboot(RB_POWER_OFF); #elif defined(__APPLE__) // TODO #elif defined(NACL) //do nothing #else syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, 0); #endif return 1; case POWERSTATE_REBOOT: // REBOOT #if defined(_ANDROID) || defined(__APPLE__) reboot(RB_AUTOBOOT); #elif defined(NACL) //do nothing #else syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART, 0); #endif return 1; case POWERSTATE_SLEEP: // SLEEP #if defined(__APPLE__) { io_connect_t port = IOPMFindPowerManagement(MACH_PORT_NULL); IOPMSleepSystem(port); IOServiceClose(port); } #endif break; #ifdef LINUX_REBOOT_CMD_SW_SUSPEND case POWERSTATE_HIBERNATE: // HIBERNATE #if defined(_ANDROID) || defined(__APPLE__) // TODO #else syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_SW_SUSPEND, 0); #endif return 1; #endif case POWERSTATE_VIBRATE: // VIBRATE #if defined(ANDROID) { ai_vibrate(1000); } #endif break; case POWERSTATE_FLASH: // FLASH #if defined(ANDROID) { ai_flash(1000); } #endif break; } return 0; } #endif #endif