2013-07-04 20:56:19 +00:00
/*
* ZeroTier One - Global Peer to Peer Ethernet
2014-02-16 20:40:22 +00:00
* Copyright ( C ) 2011 - 2014 ZeroTier Networks LLC
2013-07-04 20:56:19 +00:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*
* - -
*
* ZeroTier may be used and distributed under the terms of the GPLv3 , which
* are available at : http : //www.gnu.org/licenses/gpl-3.0.html
*
* If you would like to embed ZeroTier into a commercial application or
* redistribute it in a modified binary form , please contact ZeroTier Networks
* LLC . Start here : http : //www.zerotier.com/
*/
2014-08-22 00:49:05 +00:00
// Uncomment on Windows to assume -C and run in console instead of service
// Useful for Visual Studio debugging (launch VS as Administrator to run)
2014-08-22 00:49:46 +00:00
//#define ZT_WIN_RUN_IN_CONSOLE
2014-08-22 00:49:05 +00:00
2013-07-04 20:56:19 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <time.h>
# include <errno.h>
2013-08-26 21:22:20 +00:00
2013-07-04 20:56:19 +00:00
# include <string>
# include <stdexcept>
2013-08-10 14:27:53 +00:00
# include "node/Constants.hpp"
# ifdef __WINDOWS__
2013-08-26 21:22:20 +00:00
# include <WinSock2.h>
2013-07-04 20:56:19 +00:00
# include <Windows.h>
2013-08-26 21:22:20 +00:00
# include <tchar.h>
# include <wchar.h>
2014-01-22 00:49:34 +00:00
# include <lmcons.h>
2014-03-03 18:23:19 +00:00
# include <newdev.h>
2014-08-13 00:20:34 +00:00
# include <atlbase.h>
2014-02-06 00:37:50 +00:00
# include "windows/ZeroTierOne/ServiceInstaller.h"
# include "windows/ZeroTierOne/ServiceBase.h"
2014-02-07 06:06:27 +00:00
# include "windows/ZeroTierOne/ZeroTierOneService.h"
2013-07-04 20:56:19 +00:00
# else
# include <unistd.h>
# include <pwd.h>
2013-12-10 23:30:53 +00:00
# include <fcntl.h>
2013-07-04 20:56:19 +00:00
# include <sys/types.h>
# include <sys/stat.h>
# include <signal.h>
# endif
2013-08-26 21:22:20 +00:00
# include "node/Constants.hpp"
2014-08-06 23:24:30 +00:00
2013-08-26 21:22:20 +00:00
# include "node/Defaults.hpp"
2013-07-04 20:56:19 +00:00
# include "node/Utils.hpp"
2013-08-26 21:22:20 +00:00
# include "node/Node.hpp"
2013-12-04 22:44:28 +00:00
# include "node/C25519.hpp"
# include "node/Identity.hpp"
2014-03-19 22:29:00 +00:00
# include "node/Thread.hpp"
2014-05-06 00:15:21 +00:00
# include "node/CertificateOfMembership.hpp"
2014-08-06 23:24:30 +00:00
# include "node/EthernetTapFactory.hpp"
# include "node/RoutingTable.hpp"
# ifdef __WINDOWS__
# include "osnet/WindowsEthernetTapFactory.hpp"
# include "osnet/WindowsRoutingTable.hpp"
# define ZTCreatePlatformEthernetTapFactory (new WindowsEthernetTapFactory(homeDir))
# define ZTCreatePlatformRoutingTable (new WindowsRoutingTable())
# endif
# ifdef __LINUX__
# include "osnet/LinuxEthernetTapFactory.hpp"
# include "osnet/LinuxRoutingTable.hpp"
# define ZTCreatePlatformEthernetTapFactory (new LinuxEthernetTapFactory())
# define ZTCreatePlatformRoutingTable (new LinuxRoutingTable())
# endif
# ifdef __APPLE__
# include "osnet/OSXEthernetTapFactory.hpp"
# include "osnet/BSDRoutingTable.hpp"
# define ZTCreatePlatformEthernetTapFactory (new OSXEthernetTapFactory(homeDir,"tap.kext"))
# define ZTCreatePlatformRoutingTable (new BSDRoutingTable())
# endif
# ifndef ZTCreatePlatformEthernetTapFactory
# error Sorry, this platform has no osnet / implementation yet. Fork me on GitHub and add one?
# endif
2013-07-04 20:56:19 +00:00
using namespace ZeroTier ;
static Node * node = ( Node * ) 0 ;
2013-12-04 22:44:28 +00:00
namespace ZeroTierCLI { // ---------------------------------------------------
2013-11-08 20:23:48 +00:00
2014-03-19 22:29:00 +00:00
static void printHelp ( FILE * out , const char * cn )
2013-11-08 20:23:48 +00:00
{
2014-03-19 22:29:00 +00:00
fprintf ( out , " Usage: %s <command> (use 'help' for help) " ZT_EOL_S , cn ) ;
2013-11-08 20:23:48 +00:00
}
2014-03-19 22:29:00 +00:00
static void _CBresultHandler ( void * arg , const char * line )
2013-11-08 20:23:48 +00:00
{
2014-03-21 21:58:35 +00:00
if ( line ) {
if ( ( line [ 0 ] = = ' . ' ) & & ( line [ 1 ] = = ( char ) 0 ) )
* ( ( bool * ) arg ) = true ;
else fprintf ( stdout , " %s " ZT_EOL_S , line ) ;
}
2013-11-08 20:23:48 +00:00
}
# ifdef __WINDOWS__
2014-08-20 19:36:11 +00:00
static int main ( const char * homeDir , int argc , _TCHAR * argv [ ] )
2013-11-08 20:23:48 +00:00
# else
2014-08-20 19:36:11 +00:00
static int main ( const char * homeDir , int argc , char * * argv )
2013-11-08 20:23:48 +00:00
# endif
{
2014-03-19 22:29:00 +00:00
if ( argc < 2 ) {
2013-11-08 20:23:48 +00:00
printHelp ( stdout , argv [ 0 ] ) ;
2014-03-19 22:29:00 +00:00
return 1 ;
2013-11-08 20:23:48 +00:00
}
2014-03-19 22:29:00 +00:00
std : : string query ;
2013-11-08 20:23:48 +00:00
for ( int i = 1 ; i < argc ; + + i ) {
2014-03-19 22:29:00 +00:00
if ( argv [ i ] [ 0 ] = = ' - ' ) {
2013-11-08 20:23:48 +00:00
switch ( argv [ i ] [ 1 ] ) {
2014-03-26 00:31:03 +00:00
case ' q ' : // ignore -q since it's used to invoke this
2013-11-08 20:23:48 +00:00
break ;
2014-01-03 22:03:29 +00:00
case ' h ' :
2013-11-08 20:23:48 +00:00
default :
2014-03-19 22:29:00 +00:00
printHelp ( stdout , argv [ 0 ] ) ;
return 1 ;
2013-11-08 20:23:48 +00:00
}
} else {
2014-03-19 22:29:00 +00:00
if ( query . length ( ) )
query . push_back ( ' ' ) ;
query . append ( argv [ i ] ) ;
2013-11-08 20:23:48 +00:00
}
}
2014-03-26 00:31:03 +00:00
if ( ! query . length ( ) ) {
printHelp ( stdout , argv [ 0 ] ) ;
return 1 ;
}
2013-11-08 20:23:48 +00:00
2014-03-19 22:29:00 +00:00
try {
volatile bool done = false ;
2014-08-20 19:36:11 +00:00
Node : : NodeControlClient client ( homeDir , & _CBresultHandler , ( void * ) & done ) ;
2014-04-03 00:12:04 +00:00
const char * err = client . error ( ) ;
if ( err ) {
fprintf ( stderr , " %s: fatal error: unable to connect (is ZeroTier One running?) (%s) " ZT_EOL_S , argv [ 0 ] , err ) ;
2014-03-19 23:05:03 +00:00
return 1 ;
}
2014-03-19 22:29:00 +00:00
client . send ( query . c_str ( ) ) ;
while ( ! done )
2014-03-21 21:58:35 +00:00
Thread : : sleep ( 100 ) ; // ghetto
2014-03-19 22:29:00 +00:00
} catch ( . . . ) {
fprintf ( stderr , " %s: fatal error: unable to connect (is ZeroTier One running?) " ZT_EOL_S , argv [ 0 ] ) ;
return 1 ;
2013-11-08 20:23:48 +00:00
}
return 0 ;
}
2013-12-04 22:44:28 +00:00
} // namespace ZeroTierCLI ---------------------------------------------------
namespace ZeroTierIdTool { // ------------------------------------------------
static void printHelp ( FILE * out , const char * pn )
{
fprintf ( out , " Usage: %s <command> [<args>] " ZT_EOL_S " " ZT_EOL_S " Commands: " ZT_EOL_S , pn ) ;
fprintf ( out , " generate [<identity.secret>] [<identity.public>] " ZT_EOL_S ) ;
fprintf ( out , " validate <identity.secret/public> " ZT_EOL_S ) ;
fprintf ( out , " getpublic <identity.secret> " ZT_EOL_S ) ;
fprintf ( out , " sign <identity.secret> <file> " ZT_EOL_S ) ;
fprintf ( out , " verify <identity.secret/public> <file> <signature> " ZT_EOL_S ) ;
2014-05-06 00:05:11 +00:00
fprintf ( out , " mkcom <identity.secret> [<id,value,maxDelta> ...] (hexadecimal integers) " ZT_EOL_S ) ;
2013-12-04 22:44:28 +00:00
}
static Identity getIdFromArg ( char * arg )
{
Identity id ;
if ( ( strlen ( arg ) > 32 ) & & ( arg [ 10 ] = = ' : ' ) ) { // identity is a literal on the command line
if ( id . fromString ( arg ) )
return id ;
} else { // identity is to be read from a file
std : : string idser ;
if ( Utils : : readFile ( arg , idser ) ) {
if ( id . fromString ( idser ) )
return id ;
}
}
return Identity ( ) ;
}
# ifdef __WINDOWS__
static int main ( int argc , _TCHAR * argv [ ] )
# else
static int main ( int argc , char * * argv )
# endif
{
if ( argc < 2 ) {
2014-03-19 22:29:00 +00:00
printHelp ( stdout , argv [ 0 ] ) ;
return 1 ;
2013-12-04 22:44:28 +00:00
}
if ( ! strcmp ( argv [ 1 ] , " generate " ) ) {
Identity id ;
id . generate ( ) ;
std : : string idser = id . toString ( true ) ;
if ( argc > = 3 ) {
if ( ! Utils : : writeFile ( argv [ 2 ] , idser ) ) {
fprintf ( stderr , " Error writing to %s " ZT_EOL_S , argv [ 2 ] ) ;
2014-03-19 22:29:00 +00:00
return 1 ;
2013-12-04 22:44:28 +00:00
} else printf ( " %s written " ZT_EOL_S , argv [ 2 ] ) ;
if ( argc > = 4 ) {
idser = id . toString ( false ) ;
if ( ! Utils : : writeFile ( argv [ 3 ] , idser ) ) {
fprintf ( stderr , " Error writing to %s " ZT_EOL_S , argv [ 3 ] ) ;
2014-03-19 22:29:00 +00:00
return 1 ;
2013-12-04 22:44:28 +00:00
} else printf ( " %s written " ZT_EOL_S , argv [ 3 ] ) ;
}
} else printf ( " %s " , idser . c_str ( ) ) ;
} else if ( ! strcmp ( argv [ 1 ] , " validate " ) ) {
if ( argc < 3 ) {
2014-03-19 22:29:00 +00:00
printHelp ( stdout , argv [ 0 ] ) ;
return 1 ;
2013-12-04 22:44:28 +00:00
}
Identity id = getIdFromArg ( argv [ 2 ] ) ;
if ( ! id ) {
fprintf ( stderr , " Identity argument invalid or file unreadable: %s " ZT_EOL_S , argv [ 2 ] ) ;
2014-03-19 22:29:00 +00:00
return 1 ;
2013-12-04 22:44:28 +00:00
}
if ( ! id . locallyValidate ( ) ) {
fprintf ( stderr , " %s FAILED validation. " ZT_EOL_S , argv [ 2 ] ) ;
2014-03-19 22:29:00 +00:00
return 1 ;
2013-12-04 22:44:28 +00:00
} else printf ( " %s is a valid identity " ZT_EOL_S , argv [ 2 ] ) ;
} else if ( ! strcmp ( argv [ 1 ] , " getpublic " ) ) {
if ( argc < 3 ) {
2014-03-19 22:29:00 +00:00
printHelp ( stdout , argv [ 0 ] ) ;
return 1 ;
2013-12-04 22:44:28 +00:00
}
Identity id = getIdFromArg ( argv [ 2 ] ) ;
if ( ! id ) {
fprintf ( stderr , " Identity argument invalid or file unreadable: %s " ZT_EOL_S , argv [ 2 ] ) ;
2014-03-19 22:29:00 +00:00
return 1 ;
2013-12-04 22:44:28 +00:00
}
printf ( " %s " , id . toString ( false ) . c_str ( ) ) ;
} else if ( ! strcmp ( argv [ 1 ] , " sign " ) ) {
if ( argc < 4 ) {
2014-03-19 22:29:00 +00:00
printHelp ( stdout , argv [ 0 ] ) ;
return 1 ;
2013-12-04 22:44:28 +00:00
}
Identity id = getIdFromArg ( argv [ 2 ] ) ;
if ( ! id ) {
fprintf ( stderr , " Identity argument invalid or file unreadable: %s " ZT_EOL_S , argv [ 2 ] ) ;
2014-03-19 22:29:00 +00:00
return 1 ;
2013-12-04 22:44:28 +00:00
}
if ( ! id . hasPrivate ( ) ) {
fprintf ( stderr , " %s does not contain a private key (must use private to sign) " ZT_EOL_S , argv [ 2 ] ) ;
2014-03-19 22:29:00 +00:00
return 1 ;
2013-12-04 22:44:28 +00:00
}
std : : string inf ;
if ( ! Utils : : readFile ( argv [ 3 ] , inf ) ) {
fprintf ( stderr , " %s is not readable " ZT_EOL_S , argv [ 3 ] ) ;
2014-03-19 22:29:00 +00:00
return 1 ;
2013-12-04 22:44:28 +00:00
}
2014-01-22 00:49:34 +00:00
C25519 : : Signature signature = id . sign ( inf . data ( ) , ( unsigned int ) inf . length ( ) ) ;
printf ( " %s " , Utils : : hex ( signature . data , ( unsigned int ) signature . size ( ) ) . c_str ( ) ) ;
2013-12-04 22:44:28 +00:00
} else if ( ! strcmp ( argv [ 1 ] , " verify " ) ) {
if ( argc < 4 ) {
2014-03-19 22:29:00 +00:00
printHelp ( stdout , argv [ 0 ] ) ;
return 1 ;
2013-12-04 22:44:28 +00:00
}
Identity id = getIdFromArg ( argv [ 2 ] ) ;
if ( ! id ) {
fprintf ( stderr , " Identity argument invalid or file unreadable: %s " ZT_EOL_S , argv [ 2 ] ) ;
2014-03-19 22:29:00 +00:00
return 1 ;
2013-12-04 22:44:28 +00:00
}
std : : string inf ;
if ( ! Utils : : readFile ( argv [ 3 ] , inf ) ) {
fprintf ( stderr , " %s is not readable " ZT_EOL_S , argv [ 3 ] ) ;
2014-03-19 22:29:00 +00:00
return 1 ;
2013-12-04 22:44:28 +00:00
}
std : : string signature ( Utils : : unhex ( argv [ 4 ] ) ) ;
2014-01-22 00:49:34 +00:00
if ( ( signature . length ( ) > ZT_ADDRESS_LENGTH ) & & ( id . verify ( inf . data ( ) , ( unsigned int ) inf . length ( ) , signature . data ( ) , ( unsigned int ) signature . length ( ) ) ) ) {
2013-12-04 22:44:28 +00:00
printf ( " %s signature valid " ZT_EOL_S , argv [ 3 ] ) ;
} else {
fprintf ( stderr , " %s signature check FAILED " ZT_EOL_S , argv [ 3 ] ) ;
2014-03-19 22:29:00 +00:00
return 1 ;
2013-12-04 22:44:28 +00:00
}
2014-05-06 00:15:21 +00:00
} else if ( ! strcmp ( argv [ 1 ] , " mkcom " ) ) {
if ( argc < 3 ) {
printHelp ( stdout , argv [ 0 ] ) ;
return 1 ;
}
Identity id = getIdFromArg ( argv [ 2 ] ) ;
if ( ( ! id ) | | ( ! id . hasPrivate ( ) ) ) {
fprintf ( stderr , " Identity argument invalid, does not include private key, or file unreadable: %s " ZT_EOL_S , argv [ 2 ] ) ;
return 1 ;
}
CertificateOfMembership com ;
for ( int a = 3 ; a < argc ; + + a ) {
std : : vector < std : : string > params ( Utils : : split ( argv [ a ] , " , " , " " , " " ) ) ;
if ( params . size ( ) = = 3 ) {
uint64_t qId = Utils : : hexStrToU64 ( params [ 0 ] . c_str ( ) ) ;
uint64_t qValue = Utils : : hexStrToU64 ( params [ 1 ] . c_str ( ) ) ;
uint64_t qMaxDelta = Utils : : hexStrToU64 ( params [ 2 ] . c_str ( ) ) ;
com . setQualifier ( qId , qValue , qMaxDelta ) ;
}
}
if ( ! com . sign ( id ) ) {
fprintf ( stderr , " Signature of certificate of membership failed. " ZT_EOL_S ) ;
return 1 ;
}
printf ( " %s " , com . toString ( ) . c_str ( ) ) ;
2013-12-04 22:44:28 +00:00
} else {
2014-03-19 22:29:00 +00:00
printHelp ( stdout , argv [ 0 ] ) ;
return 1 ;
2013-12-04 22:44:28 +00:00
}
return 0 ;
}
} // namespace ZeroTierIdTool ------------------------------------------------
2013-11-08 20:23:48 +00:00
2013-08-26 21:22:20 +00:00
# ifdef __UNIX_LIKE__
2014-01-30 01:24:55 +00:00
static void sighandlerHup ( int sig )
{
Node * n = node ;
if ( n )
n - > resync ( ) ;
}
2013-07-04 20:56:19 +00:00
static void sighandlerQuit ( int sig )
{
Node * n = node ;
if ( n )
2013-08-30 19:02:12 +00:00
n - > terminate ( Node : : NODE_NORMAL_TERMINATION , " terminated by signal " ) ;
2013-07-04 20:56:19 +00:00
else exit ( 0 ) ;
}
# endif
2013-08-27 20:11:39 +00:00
# ifdef __WINDOWS__
2014-02-07 06:06:27 +00:00
// Console signal handler routine to allow CTRL+C to work, mostly for testing
2014-02-28 00:28:55 +00:00
static BOOL WINAPI _winConsoleCtrlHandler ( DWORD dwCtrlType )
2013-08-27 20:11:39 +00:00
{
switch ( dwCtrlType ) {
case CTRL_C_EVENT :
case CTRL_BREAK_EVENT :
case CTRL_CLOSE_EVENT :
case CTRL_SHUTDOWN_EVENT :
Node * n = node ;
if ( n )
2013-08-30 19:02:12 +00:00
n - > terminate ( Node : : NODE_NORMAL_TERMINATION , " terminated by signal " ) ;
2013-08-27 20:11:39 +00:00
return TRUE ;
}
return FALSE ;
}
2014-01-22 00:49:34 +00:00
2014-08-08 22:53:27 +00:00
// Pokes a hole in the Windows firewall (advfirewall) for the running program
static void _winPokeAHole ( )
{
char myPath [ MAX_PATH ] ;
DWORD ps = GetModuleFileNameA ( NULL , myPath , sizeof ( myPath ) ) ;
if ( ( ps > 0 ) & & ( ps < ( DWORD ) sizeof ( myPath ) ) ) {
STARTUPINFOA startupInfo ;
PROCESS_INFORMATION processInfo ;
startupInfo . cb = sizeof ( startupInfo ) ;
memset ( & startupInfo , 0 , sizeof ( STARTUPINFOA ) ) ;
memset ( & processInfo , 0 , sizeof ( PROCESS_INFORMATION ) ) ;
if ( CreateProcessA ( NULL , ( LPSTR ) ( std : : string ( " C: \\ Windows \\ System32 \\ netsh.exe advfirewall firewall delete rule name= \" ZeroTier One \" program= \" " ) + myPath + " \" " ) . c_str ( ) , NULL , NULL , FALSE , 0 , NULL , NULL , & startupInfo , & processInfo ) ) {
WaitForSingleObject ( processInfo . hProcess , INFINITE ) ;
CloseHandle ( processInfo . hProcess ) ;
CloseHandle ( processInfo . hThread ) ;
}
startupInfo . cb = sizeof ( startupInfo ) ;
memset ( & startupInfo , 0 , sizeof ( STARTUPINFOA ) ) ;
memset ( & processInfo , 0 , sizeof ( PROCESS_INFORMATION ) ) ;
if ( CreateProcessA ( NULL , ( LPSTR ) ( std : : string ( " C: \\ Windows \\ System32 \\ netsh.exe advfirewall firewall add rule name= \" ZeroTier One \" dir=in action=allow program= \" " ) + myPath + " \" enable=yes " ) . c_str ( ) , NULL , NULL , FALSE , 0 , NULL , NULL , & startupInfo , & processInfo ) ) {
WaitForSingleObject ( processInfo . hProcess , INFINITE ) ;
CloseHandle ( processInfo . hProcess ) ;
CloseHandle ( processInfo . hThread ) ;
}
startupInfo . cb = sizeof ( startupInfo ) ;
memset ( & startupInfo , 0 , sizeof ( STARTUPINFOA ) ) ;
memset ( & processInfo , 0 , sizeof ( PROCESS_INFORMATION ) ) ;
if ( CreateProcessA ( NULL , ( LPSTR ) ( std : : string ( " C: \\ Windows \\ System32 \\ netsh.exe advfirewall firewall add rule name= \" ZeroTier One \" dir=out action=allow program= \" " ) + myPath + " \" enable=yes " ) . c_str ( ) , NULL , NULL , FALSE , 0 , NULL , NULL , & startupInfo , & processInfo ) ) {
WaitForSingleObject ( processInfo . hProcess , INFINITE ) ;
CloseHandle ( processInfo . hProcess ) ;
CloseHandle ( processInfo . hThread ) ;
}
}
}
2014-02-07 06:06:27 +00:00
// Returns true if this is running as the local administrator
2014-01-22 00:49:34 +00:00
static BOOL IsCurrentUserLocalAdministrator ( void )
{
2014-02-07 06:06:27 +00:00
BOOL fReturn = FALSE ;
DWORD dwStatus ;
DWORD dwAccessMask ;
DWORD dwAccessDesired ;
DWORD dwACLSize ;
DWORD dwStructureSize = sizeof ( PRIVILEGE_SET ) ;
PACL pACL = NULL ;
PSID psidAdmin = NULL ;
2014-01-22 00:49:34 +00:00
2014-02-07 06:06:27 +00:00
HANDLE hToken = NULL ;
HANDLE hImpersonationToken = NULL ;
2014-01-22 00:49:34 +00:00
2014-02-07 06:06:27 +00:00
PRIVILEGE_SET ps ;
GENERIC_MAPPING GenericMapping ;
2014-01-22 00:49:34 +00:00
2014-02-07 06:06:27 +00:00
PSECURITY_DESCRIPTOR psdAdmin = NULL ;
SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY ;
2014-01-22 00:49:34 +00:00
2014-02-07 06:06:27 +00:00
const DWORD ACCESS_READ = 1 ;
const DWORD ACCESS_WRITE = 2 ;
2014-01-22 00:49:34 +00:00
2014-02-07 06:06:27 +00:00
__try
{
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 ;
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 ;
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 ;
SetSecurityDescriptorGroup ( psdAdmin , psidAdmin , FALSE ) ;
SetSecurityDescriptorOwner ( psdAdmin , psidAdmin , FALSE ) ;
if ( ! IsValidSecurityDescriptor ( psdAdmin ) )
__leave ;
dwAccessDesired = ACCESS_READ ;
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 ) ;
}
2014-01-22 00:49:34 +00:00
2014-02-07 06:06:27 +00:00
return fReturn ;
2014-01-22 00:49:34 +00:00
}
# endif // __WINDOWS__
2013-08-27 20:11:39 +00:00
2014-08-20 19:36:11 +00:00
// ---------------------------------------------------------------------------
static void printHelp ( const char * cn , FILE * out )
{
fprintf ( out , " ZeroTier One version %d.%d.%d " ZT_EOL_S " (c)2011-2014 ZeroTier Networks LLC " ZT_EOL_S , Node : : versionMajor ( ) , Node : : versionMinor ( ) , Node : : versionRevision ( ) ) ;
fprintf ( out , " Licensed under the GNU General Public License v3 " ZT_EOL_S " " ZT_EOL_S ) ;
# ifdef ZT_AUTO_UPDATE
fprintf ( out , " Auto-update enabled build, will update from URL: " ZT_EOL_S ) ;
fprintf ( out , " %s " ZT_EOL_S , ZT_DEFAULTS . updateLatestNfoURL . c_str ( ) ) ;
fprintf ( out , " Update authentication signing authorities: " ZT_EOL_S ) ;
int no = 0 ;
for ( std : : map < Address , Identity > : : const_iterator sa ( ZT_DEFAULTS . updateAuthorities . begin ( ) ) ; sa ! = ZT_DEFAULTS . updateAuthorities . end ( ) ; + + sa ) {
if ( no = = 0 )
fprintf ( out , " %s " , sa - > first . toString ( ) . c_str ( ) ) ;
else fprintf ( out , " , %s " , sa - > first . toString ( ) . c_str ( ) ) ;
if ( + + no = = 6 ) {
fprintf ( out , ZT_EOL_S ) ;
no = 0 ;
}
}
fprintf ( out , ZT_EOL_S " " ZT_EOL_S ) ;
# else
fprintf ( out , " Auto-updates not enabled on this build. You must update manually. " ZT_EOL_S " " ZT_EOL_S ) ;
# endif
fprintf ( out , " Usage: %s [-switches] [home directory] [-q <query>] " ZT_EOL_S " " ZT_EOL_S , cn ) ;
fprintf ( out , " Available switches: " ZT_EOL_S ) ;
fprintf ( out , " -h - Display this help " ZT_EOL_S ) ;
fprintf ( out , " -v - Show version " ZT_EOL_S ) ;
fprintf ( out , " -p<port> - Port for UDP (default: 9993) " ZT_EOL_S ) ;
fprintf ( out , " -t<port> - Port for TCP (default: disabled) " ZT_EOL_S ) ;
# ifdef __UNIX_LIKE__
fprintf ( out , " -d - Fork and run as daemon (Unix-ish OSes) " ZT_EOL_S ) ;
# endif
fprintf ( out , " -q - Send a query to a running service (zerotier-cli) " ZT_EOL_S ) ;
fprintf ( out , " -i - Generate and manage identities (zerotier-idtool) " ZT_EOL_S ) ;
# ifdef __WINDOWS__
fprintf ( out , " -C - Run from command line instead of as service (Windows) " ZT_EOL_S ) ;
fprintf ( out , " -I - Install Windows service (Windows) " ZT_EOL_S ) ;
fprintf ( out , " -R - Uninstall Windows service (Windows) " ZT_EOL_S ) ;
fprintf ( out , " -D - Load tap driver into system driver store (Windows) " ZT_EOL_S ) ;
# endif
}
2013-08-26 21:22:20 +00:00
# ifdef __WINDOWS__
int _tmain ( int argc , _TCHAR * argv [ ] )
# else
2013-07-04 20:56:19 +00:00
int main ( int argc , char * * argv )
2013-08-26 21:22:20 +00:00
# endif
2013-07-04 20:56:19 +00:00
{
2013-08-26 21:22:20 +00:00
# ifdef __UNIX_LIKE__
2014-01-30 01:24:55 +00:00
signal ( SIGHUP , & sighandlerHup ) ;
2013-07-04 20:56:19 +00:00
signal ( SIGPIPE , SIG_IGN ) ;
2013-07-17 18:39:34 +00:00
signal ( SIGUSR1 , SIG_IGN ) ;
signal ( SIGUSR2 , SIG_IGN ) ;
2013-07-04 20:56:19 +00:00
signal ( SIGALRM , SIG_IGN ) ;
signal ( SIGINT , & sighandlerQuit ) ;
signal ( SIGTERM , & sighandlerQuit ) ;
signal ( SIGQUIT , & sighandlerQuit ) ;
2014-04-10 18:17:54 +00:00
/* Ensure that there are no inherited file descriptors open from a previous
* incarnation . This is a hack to ensure that GitHub issue # 61 or variants
* of it do not return , and should not do anything otherwise bad . */
{
int mfd = STDIN_FILENO ;
if ( STDOUT_FILENO > mfd ) mfd = STDOUT_FILENO ;
if ( STDERR_FILENO > mfd ) mfd = STDERR_FILENO ;
for ( int f = mfd + 1 ; f < 1024 ; + + f )
: : close ( f ) ;
}
2013-07-04 20:56:19 +00:00
# endif
2013-08-26 21:22:20 +00:00
# ifdef __WINDOWS__
WSADATA wsaData ;
WSAStartup ( MAKEWORD ( 2 , 2 ) , & wsaData ) ;
# endif
2013-08-10 14:27:53 +00:00
2013-11-08 20:23:48 +00:00
if ( ( strstr ( argv [ 0 ] , " zerotier-cli " ) ) | | ( strstr ( argv [ 0 ] , " ZEROTIER-CLI " ) ) )
2014-08-20 19:36:11 +00:00
return ZeroTierCLI : : main ( ( const char * ) 0 , argc , argv ) ;
2013-12-04 22:44:28 +00:00
if ( ( strstr ( argv [ 0 ] , " zerotier-idtool " ) ) | | ( strstr ( argv [ 0 ] , " ZEROTIER-IDTOOL " ) ) )
return ZeroTierIdTool : : main ( argc , argv ) ;
2013-11-08 20:23:48 +00:00
2013-07-04 20:56:19 +00:00
const char * homeDir = ( const char * ) 0 ;
2014-03-28 01:22:53 +00:00
unsigned int udpPort = ZT_DEFAULT_UDP_PORT ;
unsigned int tcpPort = 0 ;
2014-08-22 00:49:05 +00:00
2014-03-03 19:53:43 +00:00
# ifdef __UNIX_LIKE__
bool runAsDaemon = false ;
# endif
2014-02-07 06:06:27 +00:00
# ifdef __WINDOWS__
2014-08-22 00:49:05 +00:00
# ifdef ZT_WIN_RUN_IN_CONSOLE
bool winRunFromCommandLine = true ;
# else
2014-02-07 06:06:27 +00:00
bool winRunFromCommandLine = false ;
# endif
2014-08-22 00:49:05 +00:00
# endif // __WINDOWS__
2013-07-04 20:56:19 +00:00
for ( int i = 1 ; i < argc ; + + i ) {
if ( argv [ i ] [ 0 ] = = ' - ' ) {
switch ( argv [ i ] [ 1 ] ) {
2013-09-17 18:47:48 +00:00
case ' p ' :
2014-03-28 01:22:53 +00:00
udpPort = Utils : : strToUInt ( argv [ i ] + 2 ) ;
if ( udpPort > 65535 ) {
printHelp ( argv [ 0 ] , stdout ) ;
return 1 ;
}
break ;
case ' t ' :
tcpPort = Utils : : strToUInt ( argv [ i ] + 2 ) ;
if ( tcpPort > 65535 ) {
2014-03-19 22:29:00 +00:00
printHelp ( argv [ 0 ] , stdout ) ;
2013-12-11 00:38:45 +00:00
return 1 ;
2013-09-17 18:47:48 +00:00
}
break ;
2014-03-03 19:53:43 +00:00
# ifdef __UNIX_LIKE__
case ' d ' :
runAsDaemon = true ;
break ;
# endif
2013-12-05 00:29:49 +00:00
case ' v ' :
printf ( " %s " ZT_EOL_S , Node : : versionString ( ) ) ;
return 0 ;
2013-11-08 20:23:48 +00:00
case ' q ' :
if ( argv [ i ] [ 2 ] ) {
2014-03-19 22:29:00 +00:00
printHelp ( argv [ 0 ] , stdout ) ;
2013-11-08 20:23:48 +00:00
return 0 ;
2014-08-20 19:36:11 +00:00
} else return ZeroTierCLI : : main ( homeDir , argc , argv ) ;
2013-12-04 22:44:28 +00:00
case ' i ' :
if ( argv [ i ] [ 2 ] ) {
2014-03-19 22:29:00 +00:00
printHelp ( argv [ 0 ] , stdout ) ;
2013-12-04 22:44:28 +00:00
return 0 ;
} else return ZeroTierIdTool : : main ( argc , argv ) ;
2014-02-07 06:06:27 +00:00
# ifdef __WINDOWS__
case ' C ' :
winRunFromCommandLine = true ;
break ;
case ' I ' : { // install self as service
if ( IsCurrentUserLocalAdministrator ( ) ! = TRUE ) {
fprintf ( stderr , " %s: must be run as a local administrator. " ZT_EOL_S , argv [ 0 ] ) ;
return 1 ;
}
std : : string ret ( InstallService ( ZT_SERVICE_NAME , ZT_SERVICE_DISPLAY_NAME , ZT_SERVICE_START_TYPE , ZT_SERVICE_DEPENDENCIES , ZT_SERVICE_ACCOUNT , ZT_SERVICE_PASSWORD ) ) ;
if ( ret . length ( ) ) {
fprintf ( stderr , " %s: unable to install service: %s " ZT_EOL_S , argv [ 0 ] , ret . c_str ( ) ) ;
return 3 ;
}
return 0 ;
} break ;
case ' R ' : { // uninstall self as service
if ( IsCurrentUserLocalAdministrator ( ) ! = TRUE ) {
fprintf ( stderr , " %s: must be run as a local administrator. " ZT_EOL_S , argv [ 0 ] ) ;
return 1 ;
}
std : : string ret ( UninstallService ( ZT_SERVICE_NAME ) ) ;
if ( ret . length ( ) ) {
fprintf ( stderr , " %s: unable to uninstall service: %s " ZT_EOL_S , argv [ 0 ] , ret . c_str ( ) ) ;
return 3 ;
}
return 0 ;
} break ;
2014-03-03 18:23:19 +00:00
case ' D ' : { // install Windows driver (since PNPUTIL.EXE seems to be weirdly unreliable)
std : : string pathToInf ;
# ifdef _WIN64
pathToInf = ZT_DEFAULTS . defaultHomePath + " \\ tap-windows \\ x64 \\ zttap200.inf " ;
# else
pathToInf = ZT_DEFAULTS . defaultHomePath + " \\ tap-windows \\ x86 \\ zttap200.inf " ;
# endif
2014-03-07 22:25:24 +00:00
printf ( " Installing ZeroTier One virtual Ethernet port driver. " ZT_EOL_S " " ZT_EOL_S " NOTE: If you don't see a confirmation window to allow driver installation, " ZT_EOL_S " check to make sure it didn't appear under the installer. " ZT_EOL_S ) ;
2014-03-03 18:23:19 +00:00
BOOL needReboot = FALSE ;
if ( DiInstallDriverA ( NULL , pathToInf . c_str ( ) , DIIRFLAG_FORCE_INF , & needReboot ) ) {
2014-03-06 22:06:31 +00:00
printf ( " %s: driver successfully installed from %s " ZT_EOL_S , argv [ 0 ] , pathToInf . c_str ( ) ) ;
2014-03-03 18:23:19 +00:00
return 0 ;
} else {
2014-03-06 22:06:31 +00:00
printf ( " %s: failed installing %s: %d " ZT_EOL_S , argv [ 0 ] , pathToInf . c_str ( ) , ( int ) GetLastError ( ) ) ;
2014-03-03 18:23:19 +00:00
return 3 ;
}
} break ;
2014-02-28 00:28:55 +00:00
# endif // __WINDOWS__
2013-08-26 21:22:20 +00:00
case ' h ' :
case ' ? ' :
2013-07-04 20:56:19 +00:00
default :
2014-03-19 22:29:00 +00:00
printHelp ( argv [ 0 ] , stdout ) ;
2013-08-30 19:02:12 +00:00
return 0 ;
2013-07-04 20:56:19 +00:00
}
} else {
if ( homeDir ) {
2014-03-19 22:29:00 +00:00
printHelp ( argv [ 0 ] , stdout ) ;
2013-08-30 19:02:12 +00:00
return 0 ;
2014-05-23 22:21:28 +00:00
} else homeDir = argv [ i ] ;
2013-07-04 20:56:19 +00:00
}
}
2013-08-26 21:22:20 +00:00
if ( ( ! homeDir ) | | ( strlen ( homeDir ) = = 0 ) )
homeDir = ZT_DEFAULTS . defaultHomePath . c_str ( ) ;
# ifdef __UNIX_LIKE__
2014-03-03 19:53:43 +00:00
if ( getuid ( ) ! = 0 ) {
fprintf ( stderr , " %s: must be run as root (uid 0) \n " , argv [ 0 ] ) ;
2013-12-11 00:38:45 +00:00
return 1 ;
}
2014-03-03 19:53:43 +00:00
if ( runAsDaemon ) {
long p = ( long ) fork ( ) ;
if ( p < 0 ) {
fprintf ( stderr , " %s: could not fork " ZT_EOL_S , argv [ 0 ] ) ;
return 1 ;
} else if ( p > 0 )
return 0 ; // forked
// else p == 0, so we are daemonized
}
mkdir ( homeDir , 0755 ) ; // will fail if it already exists, but that's fine
2013-11-06 19:43:47 +00:00
{
2014-02-28 00:28:55 +00:00
// Write .pid file to home folder
2013-11-06 19:43:47 +00:00
char pidpath [ 4096 ] ;
2013-11-08 16:42:11 +00:00
Utils : : snprintf ( pidpath , sizeof ( pidpath ) , " %s/zerotier-one.pid " , homeDir ) ;
2013-11-06 19:43:47 +00:00
FILE * pf = fopen ( pidpath , " w " ) ;
if ( pf ) {
fprintf ( pf , " %ld " , ( long ) getpid ( ) ) ;
fclose ( pf ) ;
}
}
2014-08-06 23:24:30 +00:00
# endif // __UNIX_LIKE__
2013-07-04 20:56:19 +00:00
2014-01-22 00:49:34 +00:00
# ifdef __WINDOWS__
2014-08-08 22:53:27 +00:00
_winPokeAHole ( ) ;
2014-02-28 00:28:55 +00:00
if ( winRunFromCommandLine ) {
// Running in "interactive" mode (mostly for debugging)
if ( IsCurrentUserLocalAdministrator ( ) ! = TRUE ) {
fprintf ( stderr , " %s: must be run as a local administrator. " ZT_EOL_S , argv [ 0 ] ) ;
return 1 ;
}
SetConsoleCtrlHandler ( & _winConsoleCtrlHandler , TRUE ) ;
// continues on to ordinary command line execution code below...
} else {
// Running from service manager
2014-02-07 06:06:27 +00:00
ZeroTierOneService zt1Service ;
if ( CServiceBase : : Run ( zt1Service ) = = TRUE ) {
return 0 ;
} else {
fprintf ( stderr , " %s: unable to start service (try -h for help) " ZT_EOL_S , argv [ 0 ] ) ;
return 1 ;
}
2014-02-28 00:28:55 +00:00
}
2014-08-06 23:24:30 +00:00
# endif // __WINDOWS__
2014-02-28 00:28:55 +00:00
int exitCode = 0 ;
2014-03-19 22:29:00 +00:00
bool needsReset = false ;
2014-08-08 02:08:41 +00:00
EthernetTapFactory * tapFactory = ( EthernetTapFactory * ) 0 ;
RoutingTable * routingTable = ( RoutingTable * ) 0 ;
2014-02-28 00:28:55 +00:00
try {
2014-08-08 02:08:41 +00:00
tapFactory = ZTCreatePlatformEthernetTapFactory ;
routingTable = ZTCreatePlatformRoutingTable ;
2014-08-06 23:24:30 +00:00
node = new Node ( homeDir , tapFactory , routingTable , udpPort , tcpPort , needsReset ) ;
2014-08-07 15:41:57 +00:00
2014-02-28 00:28:55 +00:00
switch ( node - > run ( ) ) {
2014-02-26 22:37:21 +00:00
# ifdef __WINDOWS__
2014-02-28 00:28:55 +00:00
case Node : : NODE_RESTART_FOR_UPGRADE : {
const char * upgPath = node - > reasonForTermination ( ) ;
if ( upgPath ) {
if ( ! ZeroTierOneService : : doStartUpgrade ( std : : string ( upgPath ) ) ) {
2014-02-26 22:37:21 +00:00
exitCode = 3 ;
2014-02-28 00:28:55 +00:00
fprintf ( stderr , " %s: abnormal termination: unable to execute update at %s (doStartUpgrade failed) \n " , argv [ 0 ] , ( upgPath ) ? upgPath : " (unknown path) " ) ;
2014-02-07 06:06:27 +00:00
}
2014-02-28 00:28:55 +00:00
} else {
2014-02-07 06:06:27 +00:00
exitCode = 3 ;
2014-02-28 00:28:55 +00:00
fprintf ( stderr , " %s: abnormal termination: unable to execute update at %s (no upgrade path provided) \n " , argv [ 0 ] , ( upgPath ) ? upgPath : " (unknown path) " ) ;
}
} break ;
# else // __UNIX_LIKE__
case Node : : NODE_RESTART_FOR_UPGRADE : {
const char * upgPath = node - > reasonForTermination ( ) ;
// 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 ( ) ) ;
2014-08-07 13:35:54 +00:00
std : : string updateLogPath ( homeDir ) ;
updateLogPath . append ( " /autoupdate.log " ) ;
Utils : : rm ( updateLogPath . c_str ( ) ) ;
Utils : : redirectUnixOutputs ( updateLogPath . c_str ( ) , ( const char * ) 0 ) ;
2014-02-28 00:28:55 +00:00
: : execl ( upgPath , upgPath , ( char * ) 0 ) ;
}
exitCode = 3 ;
fprintf ( stderr , " %s: abnormal termination: unable to execute update at %s \n " , argv [ 0 ] , ( upgPath ) ? upgPath : " (unknown path) " ) ;
} break ;
2014-08-07 13:35:54 +00:00
# endif // __WINDOWS__ / __UNIX_LIKE__
2014-08-07 15:41:57 +00:00
2014-02-28 00:28:55 +00:00
case Node : : NODE_UNRECOVERABLE_ERROR : {
exitCode = 3 ;
const char * termReason = node - > reasonForTermination ( ) ;
fprintf ( stderr , " %s: abnormal termination: %s \n " , argv [ 0 ] , ( termReason ) ? termReason : " (unknown reason) " ) ;
} break ;
2014-08-07 15:41:57 +00:00
2014-02-28 00:28:55 +00:00
default :
break ;
2013-11-06 19:43:47 +00:00
}
2014-08-07 15:41:57 +00:00
2014-02-28 00:28:55 +00:00
delete node ;
node = ( Node * ) 0 ;
2014-08-07 15:41:57 +00:00
} catch ( std : : exception & exc ) {
fprintf ( stderr , " %s: unexpected exception: %s " ZT_EOL_S , argv [ 0 ] , exc . what ( ) ) ;
exitCode = 3 ;
2014-02-28 00:28:55 +00:00
} catch ( . . . ) {
2014-08-07 15:41:57 +00:00
fprintf ( stderr , " %s: unexpected exception: unknown exception " ZT_EOL_S , argv [ 0 ] ) ;
2014-02-28 00:28:55 +00:00
exitCode = 3 ;
}
2014-08-08 02:08:41 +00:00
delete routingTable ;
delete tapFactory ;
2013-11-06 19:43:47 +00:00
# ifdef __UNIX_LIKE__
2014-02-28 00:28:55 +00:00
Utils : : rm ( ( std : : string ( homeDir ) + " /zerotier-one.pid " ) . c_str ( ) ) ;
2013-11-06 19:43:47 +00:00
# endif
2014-02-28 00:28:55 +00:00
return exitCode ;
2013-07-04 20:56:19 +00:00
}