From e1727d6297033881c9a379480aeacff806df2f2a Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 12 Jan 2017 14:34:52 -0800 Subject: Fix to software update repeat downloads. --- make-mac.mk | 2 +- service/SoftwareUpdater.cpp | 121 ++++++++++++++++++++++++-------------------- service/SoftwareUpdater.hpp | 19 +++++-- 3 files changed, 82 insertions(+), 60 deletions(-) diff --git a/make-mac.mk b/make-mac.mk index 1f130a1b..03c2f374 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -24,7 +24,7 @@ ifeq ($(ZT_OFFICIAL_RELEASE),1) CODESIGN_APP_CERT="Developer ID Application: ZeroTier, Inc (8ZD9JUCZ4V)" CODESIGN_INSTALLER_CERT="Developer ID Installer: ZeroTier, Inc (8ZD9JUCZ4V)" else - DEFS+=-DZT_SOFTWARE_UPDATE_DEFAULT="\"download\"" + DEFS+=-DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\"" endif ifeq ($(ZT_ENABLE_CLUSTER),1) diff --git a/service/SoftwareUpdater.cpp b/service/SoftwareUpdater.cpp index 0f5b4fca..c47a5faf 100644 --- a/service/SoftwareUpdater.cpp +++ b/service/SoftwareUpdater.cpp @@ -258,9 +258,10 @@ SoftwareUpdater::SoftwareUpdater(Node &node,const std::string &homePath) : _lastCheckTime(0), _homePath(homePath), _channel(ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL), - _latestBinLength(0), - _latestBinValid(false) + _latestValid(false), + _downloadLength(0) { + // Check for a cached newer update. If there's a cached update that is not newer, delete. } SoftwareUpdater::~SoftwareUpdater() @@ -286,6 +287,7 @@ void SoftwareUpdater::setUpdateDistribution(bool distribute) uint8_t sha512[ZT_SHA512_DIGEST_LEN]; SHA512::hash(sha512,d.bin.data(),(unsigned int)d.bin.length()); if (!memcmp(sha512,metaHash.data(),ZT_SHA512_DIGEST_LEN)) { // double check that hash in JSON is correct + d.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE] = d.bin.length(); // override with correct value -- setting this in meta json is optional _dist[Array(sha512)] = d; printf("update-dist.d: %s\n",u->c_str()); } @@ -351,19 +353,24 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void if ((len <= ZT_SOFTWARE_UPDATE_MAX_SIZE)&&(hash.length() >= 16)) { if (_latestMeta != req) { _latestMeta = req; - _latestBin = ""; - memcpy(_latestBinHashPrefix.data,hash.data(),16); - _latestBinLength = len; - _latestBinValid = false; - printf("<< LATEST\n%s\n",OSUtils::jsonDump(req).c_str()); + _latestValid = false; + + OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S + ZT_SOFTWARE_UPDATE_META_FILENAME).c_str()); + OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S + ZT_SOFTWARE_UPDATE_BIN_FILENAME).c_str()); + + _download = std::string(); + memcpy(_downloadHashPrefix.data,hash.data(),16); + _downloadLength = len; } - Buffer<128> gd; - gd.append((uint8_t)VERB_GET_DATA); - gd.append(_latestBinHashPrefix.data,16); - gd.append((uint32_t)_latestBin.length()); - _node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); - printf(">> GET_DATA @%u\n",(unsigned int)_latestBin.length()); + if ((_downloadLength > 0)&&(_download.length() < _downloadLength)) { + Buffer<128> gd; + gd.append((uint8_t)VERB_GET_DATA); + gd.append(_downloadHashPrefix.data,16); + gd.append((uint32_t)_download.length()); + _node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); + printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); + } } } @@ -379,7 +386,7 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void idx |= (unsigned long)*(reinterpret_cast(data) + 20); printf("<< GET_DATA @%u from %.10llx for %s\n",(unsigned int)idx,origin,Utils::hex(reinterpret_cast(data) + 1,16).c_str()); std::map< Array,_D >::iterator d(_dist.find(Array(reinterpret_cast(data) + 1))); - if ((d != _dist.end())&&(idx < d->second.bin.length())) { + if ((d != _dist.end())&&(idx < (unsigned long)d->second.bin.length())) { Buffer buf; buf.append((uint8_t)VERB_DATA); buf.append(reinterpret_cast(data) + 1,16); @@ -392,21 +399,21 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void break; case VERB_DATA: - if ((len >= 21)&&(!memcmp(_latestBinHashPrefix.data,reinterpret_cast(data) + 1,16))) { + if ((len >= 21)&&(_downloadLength > 0)&&(!memcmp(_downloadHashPrefix.data,reinterpret_cast(data) + 1,16))) { unsigned long idx = (unsigned long)*(reinterpret_cast(data) + 17) << 24; idx |= (unsigned long)*(reinterpret_cast(data) + 18) << 16; idx |= (unsigned long)*(reinterpret_cast(data) + 19) << 8; idx |= (unsigned long)*(reinterpret_cast(data) + 20); - printf("<< DATA @%u / %u bytes (we now have %u bytes)\n",(unsigned int)idx,(unsigned int)(len - 21),(unsigned int)_latestBin.length()); - if (idx == _latestBin.length()) { - _latestBin.append(reinterpret_cast(data) + 21,len - 21); - if (_latestBin.length() < _latestBinLength) { + printf("<< DATA @%u / %u bytes (we now have %u bytes)\n",(unsigned int)idx,(unsigned int)(len - 21),(unsigned int)_download.length()); + if (idx == (unsigned long)_download.length()) { + _download.append(reinterpret_cast(data) + 21,len - 21); + if (_download.length() < _downloadLength) { Buffer<128> gd; gd.append((uint8_t)VERB_GET_DATA); - gd.append(_latestBinHashPrefix.data,16); - gd.append((uint32_t)_latestBin.length()); + gd.append(_downloadHashPrefix.data,16); + gd.append((uint32_t)_download.length()); _node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); - printf(">> GET_DATA @%u\n",(unsigned int)_latestBin.length()); + printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); } } } @@ -447,44 +454,50 @@ bool SoftwareUpdater::check(const uint64_t now) printf(">> GET_LATEST\n"); } - if (_latestBinLength > 0) { - if (_latestBin.length() >= _latestBinLength) { - if (_latestBinValid) { - return true; - } else { - // This is the very important security validation part that makes sure - // this software update doesn't have cooties. - - try { - // (1) Check the hash itself to make sure the image is basically okay - uint8_t sha512[ZT_SHA512_DIGEST_LEN]; - SHA512::hash(sha512,_latestBin.data(),(unsigned int)_latestBin.length()); - if (Utils::hex(sha512,ZT_SHA512_DIGEST_LEN) == OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH],"~")) { - // (2) Check signature by signing authority - std::string sig(OSUtils::jsonBinFromHex(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNATURE])); - if (Identity(ZT_SOFTWARE_UPDATE_SIGNING_AUTHORITY).verify(_latestBin.data(),(unsigned int)_latestBin.length(),sig.data(),(unsigned int)sig.length())) { - // If we passed both of these, the update is good! - _latestBinValid = true; + if (_latestValid) + return true; + + if (_downloadLength > 0) { + if (_download.length() >= _downloadLength) { + // This is the very important security validation part that makes sure + // this software update doesn't have cooties. + + try { + // (1) Check the hash itself to make sure the image is basically okay + uint8_t sha512[ZT_SHA512_DIGEST_LEN]; + SHA512::hash(sha512,_download.data(),(unsigned int)_download.length()); + if (Utils::hex(sha512,ZT_SHA512_DIGEST_LEN) == OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH],"~")) { + // (2) Check signature by signing authority + std::string sig(OSUtils::jsonBinFromHex(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNATURE])); + if (Identity(ZT_SOFTWARE_UPDATE_SIGNING_AUTHORITY).verify(_download.data(),(unsigned int)_download.length(),sig.data(),(unsigned int)sig.length())) { + // If we passed both of these, the update is good! + if (OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S + ZT_SOFTWARE_UPDATE_META_FILENAME).c_str(),OSUtils::jsonDump(_latestMeta)) && OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S + ZT_SOFTWARE_UPDATE_BIN_FILENAME).c_str(),_download)) { + _latestValid = true; printf("VALID UPDATE\n%s\n",OSUtils::jsonDump(_latestMeta).c_str()); - return true; + } else { + _latestMeta = nlohmann::json(); + _latestValid = false; } + _download = std::string(); + _downloadLength = 0; + return _latestValid; } - } catch ( ... ) {} // any exception equals verification failure - printf("INVALID UPDATE (!!!)\n%s\n",OSUtils::jsonDump(_latestMeta).c_str()); - - // If we get here, checks failed. - _latestMeta = nlohmann::json(); - _latestBin = ""; - _latestBinLength = 0; - _latestBinValid = false; - } + } + } catch ( ... ) {} // any exception equals verification failure + + // If we get here, checks failed. + printf("INVALID UPDATE (!!!)\n%s\n",OSUtils::jsonDump(_latestMeta).c_str()); + _latestMeta = nlohmann::json(); + _latestValid = false; + _download = std::string(); + _downloadLength = 0; } else { Buffer<128> gd; gd.append((uint8_t)VERB_GET_DATA); - gd.append(_latestBinHashPrefix.data,16); - gd.append((uint32_t)_latestBin.length()); + gd.append(_downloadHashPrefix.data,16); + gd.append((uint32_t)_download.length()); _node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); - printf(">> GET_DATA @%u\n",(unsigned int)_latestBin.length()); + printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); } } @@ -493,8 +506,6 @@ bool SoftwareUpdater::check(const uint64_t now) void SoftwareUpdater::apply() { - if ((_latestBin.length() > 0)&&(_latestBinValid)) { - } } } // namespace ZeroTier diff --git a/service/SoftwareUpdater.hpp b/service/SoftwareUpdater.hpp index b9cabf23..26e44f86 100644 --- a/service/SoftwareUpdater.hpp +++ b/service/SoftwareUpdater.hpp @@ -69,6 +69,16 @@ */ #define ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL "release" +/** + * Filename for latest update's meta JSON + */ +#define ZT_SOFTWARE_UPDATE_META_FILENAME "latest-update.json" + +/** + * Filename for latest update's binary image + */ +#define ZT_SOFTWARE_UPDATE_BIN_FILENAME "latest-update.exe" + #define ZT_SOFTWARE_UPDATE_JSON_VERSION_MAJOR "versionMajor" #define ZT_SOFTWARE_UPDATE_JSON_VERSION_MINOR "versionMinor" #define ZT_SOFTWARE_UPDATE_JSON_VERSION_REVISION "versionRev" @@ -188,10 +198,11 @@ private: std::map< Array,_D > _dist; // key is first 16 bytes of hash nlohmann::json _latestMeta; - std::string _latestBin; - Array _latestBinHashPrefix; - unsigned long _latestBinLength; - bool _latestBinValid; + bool _latestValid; + + std::string _download; + Array _downloadHashPrefix; + unsigned long _downloadLength; }; } // namespace ZeroTier -- cgit v1.2.3 From 84bfec8329f0319dad2eae91271b879cdfb68682 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 12 Jan 2017 14:35:52 -0800 Subject: . --- make-mac.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make-mac.mk b/make-mac.mk index 03c2f374..1f130a1b 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -24,7 +24,7 @@ ifeq ($(ZT_OFFICIAL_RELEASE),1) CODESIGN_APP_CERT="Developer ID Application: ZeroTier, Inc (8ZD9JUCZ4V)" CODESIGN_INSTALLER_CERT="Developer ID Installer: ZeroTier, Inc (8ZD9JUCZ4V)" else - DEFS+=-DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\"" + DEFS+=-DZT_SOFTWARE_UPDATE_DEFAULT="\"download\"" endif ifeq ($(ZT_ENABLE_CLUSTER),1) -- cgit v1.2.3 From 8ebb49e972a0890c262692767b65efee13c4d8d0 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 12 Jan 2017 15:21:14 -0800 Subject: Cache downloaded updates to disk. --- service/SoftwareUpdater.cpp | 47 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/service/SoftwareUpdater.cpp b/service/SoftwareUpdater.cpp index c47a5faf..d6542609 100644 --- a/service/SoftwareUpdater.cpp +++ b/service/SoftwareUpdater.cpp @@ -261,7 +261,28 @@ SoftwareUpdater::SoftwareUpdater(Node &node,const std::string &homePath) : _latestValid(false), _downloadLength(0) { - // Check for a cached newer update. If there's a cached update that is not newer, delete. + // Check for a cached newer update. If there's a cached update that is not newer or looks bad, delete. + try { + std::string buf; + if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_META_FILENAME).c_str(),buf)) { + nlohmann::json meta = OSUtils::jsonParse(buf); + buf = std::string(); + const unsigned int rvMaj = (unsigned int)OSUtils::jsonInt(meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_MAJOR],0); + const unsigned int rvMin = (unsigned int)OSUtils::jsonInt(meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_MINOR],0); + const unsigned int rvRev = (unsigned int)OSUtils::jsonInt(meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_REVISION],0); + if ((Utils::compareVersion(rvMaj,rvMin,rvRev,ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION) > 0)&&(OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME).c_str(),buf))) { + if ((uint64_t)buf.length() == OSUtils::jsonInt(meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE],0)) { + _latestMeta = meta; + _latestValid = true; + printf("CACHED UPDATE IS NEWER AND LOOKS GOOD\n"); + } + } + } + } catch ( ... ) {} // exceptions indicate invalid cached update + if (!_latestValid) { + OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_META_FILENAME).c_str()); + OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME).c_str()); + } } SoftwareUpdater::~SoftwareUpdater() @@ -355,8 +376,8 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void _latestMeta = req; _latestValid = false; - OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S + ZT_SOFTWARE_UPDATE_META_FILENAME).c_str()); - OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S + ZT_SOFTWARE_UPDATE_BIN_FILENAME).c_str()); + OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_META_FILENAME).c_str()); + OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME).c_str()); _download = std::string(); memcpy(_downloadHashPrefix.data,hash.data(),16); @@ -462,6 +483,9 @@ bool SoftwareUpdater::check(const uint64_t now) // This is the very important security validation part that makes sure // this software update doesn't have cooties. + const std::string metaPath(_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_META_FILENAME); + const std::string binPath(_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME); + try { // (1) Check the hash itself to make sure the image is basically okay uint8_t sha512[ZT_SHA512_DIGEST_LEN]; @@ -470,23 +494,24 @@ bool SoftwareUpdater::check(const uint64_t now) // (2) Check signature by signing authority std::string sig(OSUtils::jsonBinFromHex(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNATURE])); if (Identity(ZT_SOFTWARE_UPDATE_SIGNING_AUTHORITY).verify(_download.data(),(unsigned int)_download.length(),sig.data(),(unsigned int)sig.length())) { - // If we passed both of these, the update is good! - if (OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S + ZT_SOFTWARE_UPDATE_META_FILENAME).c_str(),OSUtils::jsonDump(_latestMeta)) && OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S + ZT_SOFTWARE_UPDATE_BIN_FILENAME).c_str(),_download)) { + // (3) Try to save file, and if so we are good. + if (OSUtils::writeFile(metaPath.c_str(),OSUtils::jsonDump(_latestMeta)) && OSUtils::writeFile(binPath.c_str(),_download)) { + OSUtils::lockDownFile(metaPath.c_str(),false); + OSUtils::lockDownFile(binPath.c_str(),false); _latestValid = true; printf("VALID UPDATE\n%s\n",OSUtils::jsonDump(_latestMeta).c_str()); - } else { - _latestMeta = nlohmann::json(); - _latestValid = false; + _download = std::string(); + _downloadLength = 0; + return true; } - _download = std::string(); - _downloadLength = 0; - return _latestValid; } } } catch ( ... ) {} // any exception equals verification failure // If we get here, checks failed. printf("INVALID UPDATE (!!!)\n%s\n",OSUtils::jsonDump(_latestMeta).c_str()); + OSUtils::rm(metaPath.c_str()); + OSUtils::rm(binPath.c_str()); _latestMeta = nlohmann::json(); _latestValid = false; _download = std::string(); -- cgit v1.2.3 From b03247ec3c008b702f7ad28c0baaf7f93154b15f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 13 Jan 2017 10:46:16 -0800 Subject: SoftwareUpdate::apply() --- service/SoftwareUpdater.cpp | 250 +++++++------------------------------------- 1 file changed, 39 insertions(+), 211 deletions(-) diff --git a/service/SoftwareUpdater.cpp b/service/SoftwareUpdater.cpp index d6542609..cb36dceb 100644 --- a/service/SoftwareUpdater.cpp +++ b/service/SoftwareUpdater.cpp @@ -21,6 +21,20 @@ #include #include +#ifdef __WINDOWS__ +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#endif + #include "SoftwareUpdater.hpp" #include "../version.h" @@ -42,217 +56,6 @@ namespace ZeroTier { -#if 0 -#ifdef ZT_AUTO_UPDATE -#define ZT_AUTO_UPDATE_MAX_HTTP_RESPONSE_SIZE (1024 * 1024 * 64) -#define ZT_AUTO_UPDATE_CHECK_PERIOD 21600000 -class BackgroundSoftwareUpdateChecker -{ -public: - bool isValidSigningIdentity(const Identity &id) - { - return ( - /* 0001 - 0004 : obsolete, used in old versions */ - /* 0005 */ (id == Identity("ba57ea350e:0:9d4be6d7f86c5660d5ee1951a3d759aa6e12a84fc0c0b74639500f1dbc1a8c566622e7d1c531967ebceb1e9d1761342f88324a8ba520c93c35f92f35080fa23f")) - /* 0006 */ ||(id == Identity("5067b21b83:0:8af477730f5055c48135b84bed6720a35bca4c0e34be4060a4c636288b1ec22217eb22709d610c66ed464c643130c51411bbb0294eef12fbe8ecc1a1e2c63a7a")) - /* 0007 */ ||(id == Identity("4f5e97a8f1:0:57880d056d7baeb04bbc057d6f16e6cb41388570e87f01492fce882485f65a798648595610a3ad49885604e7fb1db2dd3c2c534b75e42c3c0b110ad07b4bb138")) - /* 0008 */ ||(id == Identity("580bbb8e15:0:ad5ef31155bebc6bc413991992387e083fed26d699997ef76e7c947781edd47d1997161fa56ba337b1a2b44b129fd7c7197ce5185382f06011bc88d1363b4ddd")) - ); - } - - void doUpdateCheck() - { - std::string url(OneService::autoUpdateUrl()); - if ((url.length() <= 7)||(url.substr(0,7) != "http://")) - return; - - std::string httpHost; - std::string httpPath; - { - std::size_t slashIdx = url.substr(7).find_first_of('/'); - if (slashIdx == std::string::npos) { - httpHost = url.substr(7); - httpPath = "/"; - } else { - httpHost = url.substr(7,slashIdx); - httpPath = url.substr(slashIdx + 7); - } - } - if (httpHost.length() == 0) - return; - - std::vector ips(OSUtils::resolve(httpHost.c_str())); - for(std::vector::iterator ip(ips.begin());ip!=ips.end();++ip) { - if (!ip->port()) - ip->setPort(80); - std::string nfoPath = httpPath + "LATEST.nfo"; - std::map requestHeaders,responseHeaders; - std::string body; - requestHeaders["Host"] = httpHost; - unsigned int scode = Http::GET(ZT_AUTO_UPDATE_MAX_HTTP_RESPONSE_SIZE,60000,reinterpret_cast(&(*ip)),nfoPath.c_str(),requestHeaders,responseHeaders,body); - //fprintf(stderr,"UPDATE %s %s %u %lu\n",ip->toString().c_str(),nfoPath.c_str(),scode,body.length()); - if ((scode == 200)&&(body.length() > 0)) { - /* NFO fields: - * - * file= - * signedBy= - * ed25519= - * vMajor= - * vMinor= - * vRevision= */ - Dictionary<4096> nfo(body.c_str()); - char tmp[2048]; - - if (nfo.get("vMajor",tmp,sizeof(tmp)) <= 0) return; - const unsigned int vMajor = Utils::strToUInt(tmp); - if (nfo.get("vMinor",tmp,sizeof(tmp)) <= 0) return; - const unsigned int vMinor = Utils::strToUInt(tmp); - if (nfo.get("vRevision",tmp,sizeof(tmp)) <= 0) return; - const unsigned int vRevision = Utils::strToUInt(tmp); - if (Utils::compareVersion(vMajor,vMinor,vRevision,ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION) <= 0) { - //fprintf(stderr,"UPDATE %u.%u.%u is not newer than our version\n",vMajor,vMinor,vRevision); - return; - } - - if (nfo.get("signedBy",tmp,sizeof(tmp)) <= 0) return; - Identity signedBy; - if ((!signedBy.fromString(tmp))||(!isValidSigningIdentity(signedBy))) { - //fprintf(stderr,"UPDATE invalid signedBy or not authorized signing identity.\n"); - return; - } - - if (nfo.get("file",tmp,sizeof(tmp)) <= 0) return; - std::string filePath(tmp); - if ((!filePath.length())||(filePath.find("..") != std::string::npos)) - return; - filePath = httpPath + filePath; - - std::string fileData; - if (Http::GET(ZT_AUTO_UPDATE_MAX_HTTP_RESPONSE_SIZE,60000,reinterpret_cast(&(*ip)),filePath.c_str(),requestHeaders,responseHeaders,fileData) != 200) { - //fprintf(stderr,"UPDATE GET %s failed\n",filePath.c_str()); - return; - } - - if (nfo.get("ed25519",tmp,sizeof(tmp)) <= 0) return; - std::string ed25519(Utils::unhex(tmp)); - if ((ed25519.length() == 0)||(!signedBy.verify(fileData.data(),(unsigned int)fileData.length(),ed25519.data(),(unsigned int)ed25519.length()))) { - //fprintf(stderr,"UPDATE %s failed signature check!\n",filePath.c_str()); - return; - } - - /* --------------------------------------------------------------- */ - /* We made it! Begin OS-specific installation code. */ - -#ifdef __APPLE__ - /* OSX version is in the form of a MacOSX .pkg file, so we will - * launch installer (normally in /usr/sbin) to install it. It will - * then turn around and shut down the service, update files, and - * relaunch. */ - { - char bashp[128],pkgp[128]; - Utils::snprintf(bashp,sizeof(bashp),"/tmp/ZeroTierOne-update-%u.%u.%u.sh",vMajor,vMinor,vRevision); - Utils::snprintf(pkgp,sizeof(pkgp),"/tmp/ZeroTierOne-update-%u.%u.%u.pkg",vMajor,vMinor,vRevision); - FILE *pkg = fopen(pkgp,"w"); - if ((!pkg)||(fwrite(fileData.data(),fileData.length(),1,pkg) != 1)) { - fclose(pkg); - unlink(bashp); - unlink(pkgp); - fprintf(stderr,"UPDATE error writing %s\n",pkgp); - return; - } - fclose(pkg); - FILE *bash = fopen(bashp,"w"); - if (!bash) { - fclose(pkg); - unlink(bashp); - unlink(pkgp); - fprintf(stderr,"UPDATE error writing %s\n",bashp); - return; - } - fprintf(bash, - "#!/bin/bash\n" - "export PATH=/bin:/usr/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/sbin\n" - "sleep 1\n" - "installer -pkg \"%s\" -target /\n" - "sleep 1\n" - "rm -f \"%s\" \"%s\"\n" - "exit 0\n", - pkgp, - pkgp, - bashp); - fclose(bash); - long pid = (long)vfork(); - if (pid == 0) { - setsid(); // detach from parent so that shell isn't killed when parent is killed - signal(SIGHUP,SIG_IGN); - signal(SIGTERM,SIG_IGN); - signal(SIGQUIT,SIG_IGN); - execl("/bin/bash","/bin/bash",bashp,(char *)0); - exit(0); - } - } -#endif // __APPLE__ - -#ifdef __WINDOWS__ - /* Windows version comes in the form of .MSI package that - * takes care of everything. */ - { - char tempp[512],batp[512],msip[512],cmdline[512]; - if (GetTempPathA(sizeof(tempp),tempp) <= 0) - return; - CreateDirectoryA(tempp,(LPSECURITY_ATTRIBUTES)0); - Utils::snprintf(batp,sizeof(batp),"%s\\ZeroTierOne-update-%u.%u.%u.bat",tempp,vMajor,vMinor,vRevision); - Utils::snprintf(msip,sizeof(msip),"%s\\ZeroTierOne-update-%u.%u.%u.msi",tempp,vMajor,vMinor,vRevision); - FILE *msi = fopen(msip,"wb"); - if ((!msi)||(fwrite(fileData.data(),(size_t)fileData.length(),1,msi) != 1)) { - fclose(msi); - return; - } - fclose(msi); - FILE *bat = fopen(batp,"wb"); - if (!bat) - return; - fprintf(bat, - "TIMEOUT.EXE /T 1 /NOBREAK\r\n" - "NET.EXE STOP \"ZeroTierOneService\"\r\n" - "TIMEOUT.EXE /T 1 /NOBREAK\r\n" - "MSIEXEC.EXE /i \"%s\" /qn\r\n" - "TIMEOUT.EXE /T 1 /NOBREAK\r\n" - "NET.EXE START \"ZeroTierOneService\"\r\n" - "DEL \"%s\"\r\n" - "DEL \"%s\"\r\n", - msip, - msip, - batp); - fclose(bat); - STARTUPINFOA si; - PROCESS_INFORMATION pi; - memset(&si,0,sizeof(si)); - memset(&pi,0,sizeof(pi)); - Utils::snprintf(cmdline,sizeof(cmdline),"CMD.EXE /c \"%s\"",batp); - CreateProcessA(NULL,cmdline,NULL,NULL,FALSE,CREATE_NO_WINDOW|CREATE_NEW_PROCESS_GROUP,NULL,NULL,&si,&pi); - } -#endif // __WINDOWS__ - - /* --------------------------------------------------------------- */ - - return; - } // else try to fetch from next IP address - } - } - - void threadMain() - throw() - { - try { - this->doUpdateCheck(); - } catch ( ... ) {} - } -}; -static BackgroundSoftwareUpdateChecker backgroundSoftwareUpdateChecker; -#endif // ZT_AUTO_UPDATE -#endif - SoftwareUpdater::SoftwareUpdater(Node &node,const std::string &homePath) : _node(node), _lastCheckTime(0), @@ -531,6 +334,31 @@ bool SoftwareUpdater::check(const uint64_t now) void SoftwareUpdater::apply() { + std::string updatePath(_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME); + if ((_latestMeta.is_object())&&(_latestValid)&&(OSUtils::fileExists(updatePath.c_str(),false))) { +#ifdef __WINDOWS__ + std::string cmdArgs = " "; + cmdArgs.append(OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_EXEC_ARGS],"")); + if (cmdArgs.length() == 1) cmdArgs = std::string(); + STARTUPINFOA si; + PROCESS_INFORMATION pi; + memset(&si,0,sizeof(si)); + memset(&pi,0,sizeof(pi)); + CreateProcessA(NULL,(updatePath + cmdArgs).c_str(),NULL,NULL,FALSE,CREATE_NO_WINDOW|CREATE_NEW_PROCESS_GROUP,NULL,NULL,&si,&pi); +#else + char *argv[256]; + unsigned long ac = 0; + argv[ac++] = const_cast(updatePath.c_str()); + std::vector argsSplit(OSUtils::split(OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_EXEC_ARGS],"").c_str()," ","\\","\"")); + for(std::vector::iterator a(argsSplit.begin());a!=argsSplit.end();++a) { + argv[ac] = const_cast(a->c_str()); + if (++ac == 255) break; + } + argv[ac] = (char *)0; + chmod(updatePath.c_str(),0700); + execv(updatePath.c_str(),argv); +#endif + } } } // namespace ZeroTier -- cgit v1.2.3 From 3a730c4a5ca68fdceb0acc9152b7e51812d656e7 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 13 Jan 2017 11:24:00 -0800 Subject: Remove debug printfs in software updater. It works! At least for unix. Now to test Windows. --- service/SoftwareUpdater.cpp | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/service/SoftwareUpdater.cpp b/service/SoftwareUpdater.cpp index cb36dceb..017e4f00 100644 --- a/service/SoftwareUpdater.cpp +++ b/service/SoftwareUpdater.cpp @@ -77,7 +77,7 @@ SoftwareUpdater::SoftwareUpdater(Node &node,const std::string &homePath) : if ((uint64_t)buf.length() == OSUtils::jsonInt(meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE],0)) { _latestMeta = meta; _latestValid = true; - printf("CACHED UPDATE IS NEWER AND LOOKS GOOD\n"); + //printf("CACHED UPDATE IS NEWER AND LOOKS GOOD\n"); } } } @@ -113,7 +113,7 @@ void SoftwareUpdater::setUpdateDistribution(bool distribute) if (!memcmp(sha512,metaHash.data(),ZT_SHA512_DIGEST_LEN)) { // double check that hash in JSON is correct d.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE] = d.bin.length(); // override with correct value -- setting this in meta json is optional _dist[Array(sha512)] = d; - printf("update-dist.d: %s\n",u->c_str()); + //printf("update-dist.d: %s\n",u->c_str()); } } } catch ( ... ) {} // ignore bad meta JSON, etc. @@ -193,7 +193,7 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void gd.append(_downloadHashPrefix.data,16); gd.append((uint32_t)_download.length()); _node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); - printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); + //printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); } } } @@ -208,7 +208,7 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void idx |= (unsigned long)*(reinterpret_cast(data) + 18) << 16; idx |= (unsigned long)*(reinterpret_cast(data) + 19) << 8; idx |= (unsigned long)*(reinterpret_cast(data) + 20); - printf("<< GET_DATA @%u from %.10llx for %s\n",(unsigned int)idx,origin,Utils::hex(reinterpret_cast(data) + 1,16).c_str()); + //printf("<< GET_DATA @%u from %.10llx for %s\n",(unsigned int)idx,origin,Utils::hex(reinterpret_cast(data) + 1,16).c_str()); std::map< Array,_D >::iterator d(_dist.find(Array(reinterpret_cast(data) + 1))); if ((d != _dist.end())&&(idx < (unsigned long)d->second.bin.length())) { Buffer buf; @@ -217,7 +217,7 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void buf.append((uint32_t)idx); buf.append(d->second.bin.data() + idx,std::min((unsigned long)ZT_SOFTWARE_UPDATE_CHUNK_SIZE,(unsigned long)(d->second.bin.length() - idx))); _node.sendUserMessage(origin,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,buf.data(),buf.size()); - printf(">> DATA @%u\n",(unsigned int)idx); + //printf(">> DATA @%u\n",(unsigned int)idx); } } break; @@ -228,7 +228,7 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void idx |= (unsigned long)*(reinterpret_cast(data) + 18) << 16; idx |= (unsigned long)*(reinterpret_cast(data) + 19) << 8; idx |= (unsigned long)*(reinterpret_cast(data) + 20); - printf("<< DATA @%u / %u bytes (we now have %u bytes)\n",(unsigned int)idx,(unsigned int)(len - 21),(unsigned int)_download.length()); + //printf("<< DATA @%u / %u bytes (we now have %u bytes)\n",(unsigned int)idx,(unsigned int)(len - 21),(unsigned int)_download.length()); if (idx == (unsigned long)_download.length()) { _download.append(reinterpret_cast(data) + 21,len - 21); if (_download.length() < _downloadLength) { @@ -237,7 +237,7 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void gd.append(_downloadHashPrefix.data,16); gd.append((uint32_t)_download.length()); _node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); - printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); + //printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); } } } @@ -275,7 +275,7 @@ bool SoftwareUpdater::check(const uint64_t now) (int)ZT_VENDOR_ZEROTIER, _channel.c_str()); _node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,tmp,len); - printf(">> GET_LATEST\n"); + //printf(">> GET_LATEST\n"); } if (_latestValid) @@ -302,7 +302,7 @@ bool SoftwareUpdater::check(const uint64_t now) OSUtils::lockDownFile(metaPath.c_str(),false); OSUtils::lockDownFile(binPath.c_str(),false); _latestValid = true; - printf("VALID UPDATE\n%s\n",OSUtils::jsonDump(_latestMeta).c_str()); + //printf("VALID UPDATE\n%s\n",OSUtils::jsonDump(_latestMeta).c_str()); _download = std::string(); _downloadLength = 0; return true; @@ -312,7 +312,7 @@ bool SoftwareUpdater::check(const uint64_t now) } catch ( ... ) {} // any exception equals verification failure // If we get here, checks failed. - printf("INVALID UPDATE (!!!)\n%s\n",OSUtils::jsonDump(_latestMeta).c_str()); + //printf("INVALID UPDATE (!!!)\n%s\n",OSUtils::jsonDump(_latestMeta).c_str()); OSUtils::rm(metaPath.c_str()); OSUtils::rm(binPath.c_str()); _latestMeta = nlohmann::json(); @@ -325,7 +325,7 @@ bool SoftwareUpdater::check(const uint64_t now) gd.append(_downloadHashPrefix.data,16); gd.append((uint32_t)_download.length()); _node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); - printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); + //printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); } } @@ -337,14 +337,16 @@ void SoftwareUpdater::apply() std::string updatePath(_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME); if ((_latestMeta.is_object())&&(_latestValid)&&(OSUtils::fileExists(updatePath.c_str(),false))) { #ifdef __WINDOWS__ - std::string cmdArgs = " "; - cmdArgs.append(OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_EXEC_ARGS],"")); - if (cmdArgs.length() == 1) cmdArgs = std::string(); + std::string cmdArgs(OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_EXEC_ARGS],"")); + if (cmdArgs.length() > 0) { + updatePath.push_back(' '); + updatePath.append(cmdArgs); + } STARTUPINFOA si; PROCESS_INFORMATION pi; memset(&si,0,sizeof(si)); memset(&pi,0,sizeof(pi)); - CreateProcessA(NULL,(updatePath + cmdArgs).c_str(),NULL,NULL,FALSE,CREATE_NO_WINDOW|CREATE_NEW_PROCESS_GROUP,NULL,NULL,&si,&pi); + CreateProcessA(NULL,updatePath.c_str(),NULL,NULL,FALSE,CREATE_NO_WINDOW|CREATE_NEW_PROCESS_GROUP,NULL,NULL,&si,&pi); #else char *argv[256]; unsigned long ac = 0; -- cgit v1.2.3