Browse Source

New way of doing authenticate and install. Now with more kittens.

Adam Ierymenko 11 years ago
parent
commit
99c384e110

+ 9 - 3
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

+ 52 - 31
ZeroTierUI/installdialog.cpp

@@ -38,9 +38,14 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/stat.h>
+#include <sys/types.h>
 #include <fcntl.h>
 #endif
 
+#ifdef __APPLE__
+#include "mac_doprivileged.h"
+#endif
+
 #include <QMainWindow>
 #include <QMessageBox>
 #include <QByteArray>
@@ -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;
 			}

+ 12 - 0
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

+ 24 - 0
ZeroTierUI/mac_doprivileged.mm

@@ -0,0 +1,24 @@
+#include <string.h>
+#include <stdio.h>
+
+#include "mac_doprivileged.h"
+
+#undef slots
+#include <Cocoa/Cocoa.h>
+
+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);
+}

+ 39 - 5
ZeroTierUI/mainwindow.cpp

@@ -51,6 +51,15 @@
 #include <QScrollBar>
 #include <QEventLoop>
 
+#ifdef __APPLE__
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#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