From 2498ecbc847610dfe34ab23b801572a147bd7934 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 21 Jan 2014 16:49:34 -0800 Subject: [PATCH] Windows compile fixes, check if running as administrator on startup for Windows. --- main.cpp | 216 +++++++++++++++++++++++- windows/ZeroTierOne/ZeroTierOne.vcxproj | 8 +- windows/ZeroTierOneService/Service.cs | 1 + 3 files changed, 214 insertions(+), 11 deletions(-) diff --git a/main.cpp b/main.cpp index 88c8787e9..56cc9d84b 100644 --- a/main.cpp +++ b/main.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #else #include #include @@ -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; diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj b/windows/ZeroTierOne/ZeroTierOne.vcxproj index a1c616584..f739ea1a8 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj @@ -151,22 +151,22 @@ .exe $(SolutionDir)\Build\$(Platform)\$(Configuration)\ - zerotier-one-x86 + zerotier-one_x86 .exe $(SolutionDir)\Build\$(Platform)\$(Configuration)\ - zerotier-one-x86 + zerotier-one_x86 .exe $(SolutionDir)\Build\$(Platform)\$(Configuration)\ - zerotier-one-x64 + zerotier-one_x64 .exe $(SolutionDir)\Build\$(Platform)\$(Configuration)\ - zerotier-one-x64 + zerotier-one_x64 diff --git a/windows/ZeroTierOneService/Service.cs b/windows/ZeroTierOneService/Service.cs index f706802af..4ac11bd00 100644 --- a/windows/ZeroTierOneService/Service.cs +++ b/windows/ZeroTierOneService/Service.cs @@ -45,6 +45,7 @@ namespace ZeroTierOneService private void ztService_Exited(object sender, System.EventArgs e) { + ztService = null; } private string ztHome;