From 99c384e110f34d780ba78a76de95616a6801fcfa Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 15 Jan 2014 17:00:53 -0800 Subject: New way of doing authenticate and install. Now with more kittens. --- ZeroTierUI/ZeroTierUI.pro | 12 ++++-- ZeroTierUI/installdialog.cpp | 83 ++++++++++++++++++++++++++---------------- ZeroTierUI/mac_doprivileged.h | 12 ++++++ ZeroTierUI/mac_doprivileged.mm | 24 ++++++++++++ ZeroTierUI/mainwindow.cpp | 44 +++++++++++++++++++--- 5 files changed, 136 insertions(+), 39 deletions(-) create mode 100644 ZeroTierUI/mac_doprivileged.h create mode 100644 ZeroTierUI/mac_doprivileged.mm diff --git a/ZeroTierUI/ZeroTierUI.pro b/ZeroTierUI/ZeroTierUI.pro index 6473fdb6..37857b3b 100644 --- a/ZeroTierUI/ZeroTierUI.pro +++ b/ZeroTierUI/ZeroTierUI.pro @@ -3,9 +3,11 @@ TARGET = "ZeroTier One" TEMPLATE = app win32:RC_FILE = ZeroTierUI.rc + mac:ICON = zt1icon.icns mac:QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.6 mac:QMAKE_INFO_PLIST = Info.plist +mac:LIBS += -framework Cocoa SOURCES += main.cpp\ mainwindow.cpp \ @@ -40,7 +42,7 @@ SOURCES += main.cpp\ ../ext/lz4/lz4.c \ ../ext/lz4/lz4hc.c \ networkwidget.cpp \ - installdialog.cpp + installdialog.cpp HEADERS += mainwindow.h \ aboutwindow.h \ @@ -90,12 +92,16 @@ HEADERS += mainwindow.h \ ../ext/lz4/lz4.h \ ../ext/lz4/lz4hc.h \ networkwidget.h \ - installdialog.h + installdialog.h \ + mac_doprivileged.h FORMS += mainwindow.ui \ aboutwindow.ui \ networkwidget.ui \ - installdialog.ui + installdialog.ui RESOURCES += \ resources.qrc + +mac:OBJECTIVE_SOURCES += \ + mac_doprivileged.mm diff --git a/ZeroTierUI/installdialog.cpp b/ZeroTierUI/installdialog.cpp index 66dd53dc..14ad5b6a 100644 --- a/ZeroTierUI/installdialog.cpp +++ b/ZeroTierUI/installdialog.cpp @@ -38,9 +38,14 @@ #include #include #include +#include #include #endif +#ifdef __APPLE__ +#include "mac_doprivileged.h" +#endif + #include #include #include @@ -103,45 +108,61 @@ void InstallDialog::on_networkReply(QNetworkReply *reply) } break; case FETCHING_INSTALLER: { if (!ZeroTier::SoftwareUpdater::validateUpdate(installerData.data(),installerData.length(),signedBy,signature)) { - QMessageBox::critical(this,"Download Failed","Download failed: there is a problem with the software update web site.\nTry agian later. (failed signature check)",QMessageBox::Ok,QMessageBox::NoButton); + QMessageBox::critical(this,"Download Failed","Download failed: there is a problem with the software update web site. Try agian later. (downloaded data failed signature check)",QMessageBox::Ok,QMessageBox::NoButton); QApplication::exit(1); return; } #ifdef __APPLE__ - QString zt1Caches(QDir::homePath() + "/Library/Caches/ZeroTier/One"); - QDir::root().mkpath(zt1Caches); - QString instPath(zt1Caches+"/ZeroTierOneInstaller"); - - int outfd = ::open(instPath.toStdString().c_str(),O_CREAT|O_TRUNC|O_WRONLY,0755); - if (outfd <= 0) { - QMessageBox::critical(this,"Download Failed",QString("Installation failed: unable to write to ")+instPath,QMessageBox::Ok,QMessageBox::NoButton); - QApplication::exit(1); - return; - } - if (::write(outfd,installerData.data(),installerData.length()) != installerData.length()) { - QMessageBox::critical(this,"Installation Failed",QString("Installation failed: unable to write to ")+instPath,QMessageBox::Ok,QMessageBox::NoButton); - QApplication::exit(1); - return; - } - ::close(outfd); - ::chmod(instPath.toStdString().c_str(),0755); + { + std::string homePath(QDir::homePath().toStdString()); + QString zt1Caches(QDir::homePath() + "/Library/Caches/ZeroTier/One"); + QDir::root().mkpath(zt1Caches); + std::string instPath((zt1Caches + "/ZeroTierOneInstaller").toStdString()); + std::string tmpPath((zt1Caches + "/inst.sh").toStdString()); + + int outfd = ::open(instPath.c_str(),O_CREAT|O_TRUNC|O_WRONLY,0755); + if (outfd <= 0) { + QMessageBox::critical(this,"Download Failed",QString("Installation failed: unable to write to ")+instPath.c_str(),QMessageBox::Ok,QMessageBox::NoButton); + QApplication::exit(1); + return; + } + if (::write(outfd,installerData.data(),installerData.length()) != installerData.length()) { + QMessageBox::critical(this,"Installation Failed",QString("Installation failed: unable to write to ")+instPath.c_str(),QMessageBox::Ok,QMessageBox::NoButton); + QApplication::exit(1); + return; + } + ::close(outfd); + chmod(instPath.c_str(),0755); + + FILE *scr = fopen(tmpPath.c_str(),"w"); + if (!scr) { + QMessageBox::critical(this,"Installation Failed","Cannot write script to temporary Library/Caches/ZeroTier/One folder.",QMessageBox::Ok,QMessageBox::NoButton); + QApplication::exit(1); + return; + } + + fprintf(scr,"#!/bin/bash\n"); + fprintf(scr,"export PATH=\"/bin:/usr/bin:/sbin:/usr/sbin\"\n"); + fprintf(scr,"'%s'\n",instPath.c_str()); + fprintf(scr,"if [ -f '/Library/Application Support/ZeroTier/One/authtoken.secret' ]; then\n"); + fprintf(scr," cp -f '/Library/Application Support/ZeroTier/One/authtoken.secret' '%s/Library/Application Support/ZeroTier/One/authtoken.secret'\n",homePath.c_str()); + fprintf(scr," chown %d '%s/Library/Application Support/ZeroTier/One/authtoken.secret'\n",(int)getuid(),homePath.c_str()); + fprintf(scr," chgrp %d '%s/Library/Application Support/ZeroTier/One/authtoken.secret'\n",(int)getgid(),homePath.c_str()); + fprintf(scr," chmod 0600 '%s/Library/Application Support/ZeroTier/One/authtoken.secret'\n",homePath.c_str()); + fprintf(scr,"fi\n"); + fprintf(scr,"exit 0\n"); + + fclose(scr); + chmod(tmpPath.c_str(),0755); + + macExecutePrivilegedShellCommand((std::string("'")+tmpPath+"' >>/dev/null 2>&1").c_str()); + + unlink(tmpPath.c_str()); + unlink(instPath.c_str()); - QString installHelperPath(QCoreApplication::applicationDirPath() + "/../Resources/helpers/mac/ZeroTier One (Install).app/Contents/MacOS/applet"); - if (!QFile::exists(installHelperPath)) { - QMessageBox::critical(this,"Unable to Locate Helper","Unable to locate install helper, cannot install service.",QMessageBox::Ok,QMessageBox::NoButton); - QApplication::exit(1); return; } - - // Terminate the GUI and execute the install helper instead - ::execl(installHelperPath.toStdString().c_str(),installHelperPath.toStdString().c_str(),(const char *)0); - - // We only make it here if execl() failed - QMessageBox::critical(this,"Unable to Locate Helper","Unable to locate install helper, cannot install service.",QMessageBox::Ok,QMessageBox::NoButton); - QApplication::exit(1); - - return; #endif } break; } diff --git a/ZeroTierUI/mac_doprivileged.h b/ZeroTierUI/mac_doprivileged.h new file mode 100644 index 00000000..52fba922 --- /dev/null +++ b/ZeroTierUI/mac_doprivileged.h @@ -0,0 +1,12 @@ +#ifndef mac_doprivileged_h +#define mac_doprivileged_h + +#ifdef __APPLE__ + +// commandAndArgs can contain only single-tic quotes and should redirect its +// stdout and stderr somewhere... +bool macExecutePrivilegedShellCommand(const char *commandAndArgs); + +#endif + +#endif diff --git a/ZeroTierUI/mac_doprivileged.mm b/ZeroTierUI/mac_doprivileged.mm new file mode 100644 index 00000000..5bd6a7a6 --- /dev/null +++ b/ZeroTierUI/mac_doprivileged.mm @@ -0,0 +1,24 @@ +#include +#include + +#include "mac_doprivileged.h" + +#undef slots +#include + +bool macExecutePrivilegedShellCommand(const char *commandAndArgs) +{ + char tmp[32768]; + + snprintf(tmp,sizeof(tmp),"do shell script \"%s\" with administrator privileges\n",commandAndArgs); + tmp[32767] = (char)0; + + NSString *scriptApple = [[NSString alloc] initWithUTF8String:tmp]; + NSAppleScript *as = [[NSAppleScript alloc] initWithSource:scriptApple]; + NSDictionary *err = nil; + [as executeAndReturnError:&err]; + [as release]; + [scriptApple release]; + + return (err == nil); +} diff --git a/ZeroTierUI/mainwindow.cpp b/ZeroTierUI/mainwindow.cpp index 3fd37586..4bbee8c9 100644 --- a/ZeroTierUI/mainwindow.cpp +++ b/ZeroTierUI/mainwindow.cpp @@ -51,6 +51,15 @@ #include #include +#ifdef __APPLE__ +#include +#include +#include +#include +#include +#include "mac_doprivileged.h" +#endif + QNetworkAccessManager *nam; // Globally visible @@ -121,15 +130,39 @@ void MainWindow::timerEvent(QTimerEvent *event) if (!ZeroTier::Utils::readFile(ZeroTier::Node::LocalClient::authTokenDefaultUserPath().c_str(),authToken)) { #ifdef __APPLE__ if (QFile::exists("/Library/Application Support/ZeroTier/One/zerotier-one")) { - QMessageBox::information(this,"Authorization Required","You must authenticate to authorize this user to administrate ZeroTier One on this computer.\n\n(This only needs to be done once.)",QMessageBox::Ok,QMessageBox::NoButton); - QString authHelperPath(QCoreApplication::applicationDirPath() + "/../Resources/helpers/mac/ZeroTier One (Authenticate).app/Contents/MacOS/applet"); - if (!QFile::exists(authHelperPath)) { - QMessageBox::critical(this,"Unable to Locate Helper","Unable to locate authorization helper, cannot obtain authentication token.",QMessageBox::Ok,QMessageBox::NoButton); + // Authorize user by copying auth token into local home directory + QMessageBox::information(this,"Authorization Needed","Administrator privileges are required to allow the current user to control ZeroTier One on this computer. (You only have to do this once.)",QMessageBox::Ok,QMessageBox::NoButton); + + std::string homePath(QDir::homePath().toStdString()); + QString zt1Caches(QDir::homePath() + "/Library/Caches/ZeroTier/One"); + QDir::root().mkpath(zt1Caches); + std::string tmpPath((zt1Caches + "/auth.sh").toStdString()); + + FILE *scr = fopen(tmpPath.c_str(),"w"); + if (!scr) { + QMessageBox::critical(this,"Cannot Authorize","Unable to authorize this user to administrate ZeroTier One. (Cannot write to temporary Library/Caches/ZeroTier/One folder.)",QMessageBox::Ok,QMessageBox::NoButton); QApplication::exit(1); return; } - QProcess::execute(authHelperPath,QStringList()); + + fprintf(scr,"#!/bin/bash\n"); + fprintf(scr,"export PATH=\"/bin:/usr/bin:/sbin:/usr/sbin\"\n"); + fprintf(scr,"if [ -f '/Library/Application Support/ZeroTier/One/authtoken.secret' ]; then\n"); + fprintf(scr," cp -f '/Library/Application Support/ZeroTier/One/authtoken.secret' '%s/Library/Application Support/ZeroTier/One/authtoken.secret'\n",homePath.c_str()); + fprintf(scr," chown %d '%s/Library/Application Support/ZeroTier/One/authtoken.secret'\n",(int)getuid(),homePath.c_str()); + fprintf(scr," chgrp %d '%s/Library/Application Support/ZeroTier/One/authtoken.secret'\n",(int)getgid(),homePath.c_str()); + fprintf(scr," chmod 0600 '%s/Library/Application Support/ZeroTier/One/authtoken.secret'\n",homePath.c_str()); + fprintf(scr,"fi\n"); + fprintf(scr,"exit 0\n"); + + fclose(scr); + chmod(tmpPath.c_str(),0755); + + macExecutePrivilegedShellCommand((std::string("'")+tmpPath+"' >>/dev/null 2>&1").c_str()); + + unlink(tmpPath.c_str()); } else { + // Install service and other support files if service isn't there doInstallDialog(); return; } @@ -268,6 +301,7 @@ void MainWindow::customEvent(QEvent *event) void MainWindow::showEvent(QShowEvent *event) { #ifdef __APPLE__ + // If service isn't installed, download and install it if (!QFile::exists("/Library/Application Support/ZeroTier/One/zerotier-one")) doInstallDialog(); #endif -- cgit v1.2.3