summaryrefslogtreecommitdiff
path: root/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'main.cpp')
-rw-r--r--main.cpp216
1 files changed, 209 insertions, 7 deletions
diff --git a/main.cpp b/main.cpp
index 88c8787e..56cc9d84 100644
--- a/main.cpp
+++ b/main.cpp
@@ -41,6 +41,7 @@
#include <Windows.h>
#include <tchar.h>
#include <wchar.h>
+#include <lmcons.h>
#else
#include <unistd.h>
#include <pwd.h>
@@ -317,8 +318,8 @@ static int main(int argc,char **argv)
fprintf(stderr,"%s is not readable"ZT_EOL_S,argv[3]);
return -1;
}
- C25519::Signature signature = id.sign(inf.data(),inf.length());
- printf("%s",Utils::hex(signature.data,signature.size()).c_str());
+ C25519::Signature signature = id.sign(inf.data(),(unsigned int)inf.length());
+ printf("%s",Utils::hex(signature.data,(unsigned int)signature.size()).c_str());
} else if (!strcmp(argv[1],"verify")) {
if (argc < 4) {
printHelp(stderr,argv[0]);
@@ -338,7 +339,7 @@ static int main(int argc,char **argv)
}
std::string signature(Utils::unhex(argv[4]));
- if ((signature.length() > ZT_ADDRESS_LENGTH)&&(id.verify(inf.data(),inf.length(),signature.data(),signature.length()))) {
+ if ((signature.length() > ZT_ADDRESS_LENGTH)&&(id.verify(inf.data(),(unsigned int)inf.length(),signature.data(),(unsigned int)signature.length()))) {
printf("%s signature valid"ZT_EOL_S,argv[3]);
} else {
fprintf(stderr,"%s signature check FAILED"ZT_EOL_S,argv[3]);
@@ -380,7 +381,186 @@ static BOOL WINAPI _handlerRoutine(DWORD dwCtrlType)
}
return FALSE;
}
-#endif
+
+static BOOL IsCurrentUserLocalAdministrator(void)
+{
+ BOOL fReturn = FALSE;
+ DWORD dwStatus;
+ DWORD dwAccessMask;
+ DWORD dwAccessDesired;
+ DWORD dwACLSize;
+ DWORD dwStructureSize = sizeof(PRIVILEGE_SET);
+ PACL pACL = NULL;
+ PSID psidAdmin = NULL;
+
+ HANDLE hToken = NULL;
+ HANDLE hImpersonationToken = NULL;
+
+ PRIVILEGE_SET ps;
+ GENERIC_MAPPING GenericMapping;
+
+ PSECURITY_DESCRIPTOR psdAdmin = NULL;
+ SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY;
+
+
+ /*
+ Determine if the current thread is running as a user that is a member
+
+of
+ the local admins group. To do this, create a security descriptor
+
+that
+ has a DACL which has an ACE that allows only local aministrators
+
+access.
+ Then, call AccessCheck with the current thread's token and the
+
+security
+ descriptor. It will say whether the user could access an object if
+
+it
+ had that security descriptor. Note: you do not need to actually
+
+create
+ the object. Just checking access against the security descriptor
+
+alone
+ will be sufficient.
+ */
+ const DWORD ACCESS_READ = 1;
+ const DWORD ACCESS_WRITE = 2;
+
+
+ __try
+ {
+
+ /*
+ AccessCheck() requires an impersonation token. We first get a
+
+primary
+ token and then create a duplicate impersonation token. The
+ impersonation token is not actually assigned to the thread, but is
+ used in the call to AccessCheck. Thus, this function itself never
+ impersonates, but does use the identity of the thread. If the
+
+thread
+ was impersonating already, this function uses that impersonation
+
+context.
+ */
+ if (!OpenThreadToken(GetCurrentThread(), TOKEN_DUPLICATE|TOKEN_QUERY,
+
+TRUE, &hToken))
+ {
+ if (GetLastError() != ERROR_NO_TOKEN)
+ __leave;
+
+ if (!OpenProcessToken(GetCurrentProcess(),
+
+TOKEN_DUPLICATE|TOKEN_QUERY, &hToken))
+ __leave;
+ }
+
+ if (!DuplicateToken (hToken, SecurityImpersonation,
+
+&hImpersonationToken))
+ __leave;
+
+
+ /*
+ Create the binary representation of the well-known SID that
+ represents the local administrators group. Then create the
+
+security
+ descriptor and DACL with an ACE that allows only local admins
+
+access.
+ After that, perform the access check. This will determine whether
+ the current user is a local admin.
+ */
+ if (!AllocateAndInitializeSid(&SystemSidAuthority, 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0, &psidAdmin))
+ __leave;
+
+ psdAdmin = LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
+ if (psdAdmin == NULL)
+ __leave;
+
+ if (!InitializeSecurityDescriptor(psdAdmin,
+
+SECURITY_DESCRIPTOR_REVISION))
+ __leave;
+
+ // Compute size needed for the ACL.
+ dwACLSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) +
+ GetLengthSid(psidAdmin) - sizeof(DWORD);
+
+ pACL = (PACL)LocalAlloc(LPTR, dwACLSize);
+ if (pACL == NULL)
+ __leave;
+
+ if (!InitializeAcl(pACL, dwACLSize, ACL_REVISION2))
+ __leave;
+
+ dwAccessMask= ACCESS_READ | ACCESS_WRITE;
+
+ if (!AddAccessAllowedAce(pACL, ACL_REVISION2, dwAccessMask,
+
+psidAdmin))
+ __leave;
+
+ if (!SetSecurityDescriptorDacl(psdAdmin, TRUE, pACL, FALSE))
+ __leave;
+
+ /*
+ AccessCheck validates a security descriptor somewhat; set the
+
+group
+ and owner so that enough of the security descriptor is filled out
+
+to
+ make AccessCheck happy.
+ */
+ SetSecurityDescriptorGroup(psdAdmin, psidAdmin, FALSE);
+ SetSecurityDescriptorOwner(psdAdmin, psidAdmin, FALSE);
+
+ if (!IsValidSecurityDescriptor(psdAdmin))
+ __leave;
+
+ dwAccessDesired = ACCESS_READ;
+
+ /*
+ Initialize GenericMapping structure even though you
+ do not use generic rights.
+ */
+ GenericMapping.GenericRead = ACCESS_READ;
+ GenericMapping.GenericWrite = ACCESS_WRITE;
+ GenericMapping.GenericExecute = 0;
+ GenericMapping.GenericAll = ACCESS_READ | ACCESS_WRITE;
+
+ if (!AccessCheck(psdAdmin, hImpersonationToken, dwAccessDesired,
+ &GenericMapping, &ps, &dwStructureSize, &dwStatus,
+ &fReturn))
+ {
+ fReturn = FALSE;
+ __leave;
+ }
+ }
+ __finally
+ {
+ // Clean up.
+ if (pACL) LocalFree(pACL);
+ if (psdAdmin) LocalFree(psdAdmin);
+ if (psidAdmin) FreeSid(psidAdmin);
+ if (hImpersonationToken) CloseHandle (hImpersonationToken);
+ if (hToken) CloseHandle (hToken);
+ }
+
+ return fReturn;
+}
+#endif // __WINDOWS__
#ifdef __WINDOWS__
int _tmain(int argc, _TCHAR* argv[])
@@ -477,6 +657,13 @@ int main(int argc,char **argv)
fclose(pf);
}
}
+#else
+#ifdef __WINDOWS__
+ if (IsCurrentUserLocalAdministrator() != TRUE) {
+ fprintf(stderr,"%s: must be run as a local administrator."ZT_EOL_S,argv[0]);
+ return 1;
+ }
+#endif
#endif
int exitCode = 0;
@@ -485,15 +672,30 @@ int main(int argc,char **argv)
node = new Node(homeDir,port,controlPort);
switch(node->run()) {
case Node::NODE_RESTART_FOR_UPGRADE: {
-#ifdef __UNIX_LIKE__
const char *upgPath = node->reasonForTermination();
+#ifdef __UNIX_LIKE__
+ // On Unix-type OSes we exec() right into the upgrade. This in turn will
+ // end with us being re-launched either via the upgrade itself or something
+ // like OSX's launchd.
if (upgPath) {
Utils::rm((std::string(homeDir)+"/zerotier-one.pid").c_str());
- execl(upgPath,upgPath,(char *)0);
+ ::execl(upgPath,upgPath,(char *)0);
}
exitCode = 2;
fprintf(stderr,"%s: abnormal termination: unable to execute update at %s\n",argv[0],(upgPath) ? upgPath : "(unknown path)");
-#endif
+#else // not __UNIX_LIKE
+#ifdef __WINDOWS__
+ // On Windows the service checks updates.d and invokes updates if they are
+ // found there. This only happens after exit code 4. The Windows service
+ // will listen to stdout as well to catch the filename.
+ if (upgPath) {
+ printf("[[[ UPDATE AVAILABLE: \"%s\" ]]]\r\n",upgPath);
+ exitCode = 4;
+ } else {
+ exitCode = 2;
+ }
+#endif // __WINDOWS__
+#endif // not __UNIX_LIKE__
} break;
case Node::NODE_UNRECOVERABLE_ERROR: {
exitCode = 3;