|
|
|
|
@ -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; |
|
|
|
|
|