main.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. /*
  2. * ZeroTier One - Global Peer to Peer Ethernet
  3. * Copyright (C) 2012-2013 ZeroTier Networks LLC
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * --
  19. *
  20. * ZeroTier may be used and distributed under the terms of the GPLv3, which
  21. * are available at: http://www.gnu.org/licenses/gpl-3.0.html
  22. *
  23. * If you would like to embed ZeroTier into a commercial application or
  24. * redistribute it in a modified binary form, please contact ZeroTier Networks
  25. * LLC. Start here: http://www.zerotier.com/
  26. */
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <time.h>
  31. #include <errno.h>
  32. #include <string>
  33. #include <stdexcept>
  34. #include "node/Constants.hpp"
  35. #ifdef __WINDOWS__
  36. #include <WinSock2.h>
  37. #include <Windows.h>
  38. #include <tchar.h>
  39. #include <wchar.h>
  40. #include <lmcons.h>
  41. #include "windows/ZeroTierOne/ServiceInstaller.h"
  42. #include "windows/ZeroTierOne/ServiceBase.h"
  43. #else
  44. #include <unistd.h>
  45. #include <pwd.h>
  46. #include <fcntl.h>
  47. #include <sys/types.h>
  48. #include <sys/stat.h>
  49. #include <signal.h>
  50. #endif
  51. #include "node/Constants.hpp"
  52. #include "node/Defaults.hpp"
  53. #include "node/Utils.hpp"
  54. #include "node/Node.hpp"
  55. #include "node/Condition.hpp"
  56. #include "node/C25519.hpp"
  57. #include "node/Identity.hpp"
  58. using namespace ZeroTier;
  59. static Node *node = (Node *)0;
  60. static void printHelp(const char *cn,FILE *out)
  61. {
  62. fprintf(out,"ZeroTier One version %d.%d.%d"ZT_EOL_S"(c)2012-2013 ZeroTier Networks LLC"ZT_EOL_S,Node::versionMajor(),Node::versionMinor(),Node::versionRevision());
  63. fprintf(out,"Licensed under the GNU General Public License v3"ZT_EOL_S""ZT_EOL_S);
  64. #ifdef ZT_AUTO_UPDATE
  65. fprintf(out,"Auto-update enabled build, will update from URL:"ZT_EOL_S);
  66. fprintf(out," %s"ZT_EOL_S,ZT_DEFAULTS.updateLatestNfoURL.c_str());
  67. fprintf(out,"Update authentication signing authorities: "ZT_EOL_S);
  68. int no = 0;
  69. for(std::map< Address,Identity >::const_iterator sa(ZT_DEFAULTS.updateAuthorities.begin());sa!=ZT_DEFAULTS.updateAuthorities.end();++sa) {
  70. if (no == 0)
  71. fprintf(out," %s",sa->first.toString().c_str());
  72. else fprintf(out,", %s",sa->first.toString().c_str());
  73. if (++no == 6) {
  74. fprintf(out,ZT_EOL_S);
  75. no = 0;
  76. }
  77. }
  78. fprintf(out,ZT_EOL_S""ZT_EOL_S);
  79. #else
  80. fprintf(out,"Auto-updates not enabled on this build. You must update manually."ZT_EOL_S""ZT_EOL_S);
  81. #endif
  82. fprintf(out,"Usage: %s [-switches] [home directory]"ZT_EOL_S""ZT_EOL_S,cn);
  83. fprintf(out,"Available switches:"ZT_EOL_S);
  84. fprintf(out," -h - Display this help"ZT_EOL_S);
  85. fprintf(out," -v - Show version"ZT_EOL_S);
  86. fprintf(out," -p<port> - Bind to this port for network I/O"ZT_EOL_S);
  87. fprintf(out," -c<port> - Bind to this port for local control packets"ZT_EOL_S);
  88. fprintf(out," -q - Send a query to a running service (zerotier-cli)"ZT_EOL_S);
  89. fprintf(out," -i - Run idtool command (zerotier-idtool)"ZT_EOL_S);
  90. #ifdef __WINDOWS__
  91. fprintf(out," -I - Install Windows service"ZT_EOL_S);
  92. fprintf(out," -R - Uninstall Windows service"ZT_EOL_S);
  93. #endif
  94. }
  95. namespace ZeroTierCLI { // ---------------------------------------------------
  96. static void printHelp(FILE *out,const char *exename)
  97. {
  98. fprintf(out,"Usage: %s [-switches] <command>"ZT_EOL_S,exename);
  99. fprintf(out,ZT_EOL_S);
  100. fprintf(out,"Available switches:"ZT_EOL_S);
  101. fprintf(out," -c<port> - Communicate with daemon over this local port"ZT_EOL_S);
  102. fprintf(out," -t<token> - Specify token on command line"ZT_EOL_S);
  103. fprintf(out," -T<file> - Read token from file"ZT_EOL_S);
  104. fprintf(out,ZT_EOL_S);
  105. fprintf(out,"Use the 'help' command to get help from ZeroTier One itself."ZT_EOL_S);
  106. }
  107. static volatile unsigned int numResults = 0;
  108. static Condition doneCondition;
  109. static void resultHandler(void *arg,unsigned long id,const char *line)
  110. {
  111. ++numResults;
  112. if (strlen(line))
  113. fprintf(stdout,"%s"ZT_EOL_S,line);
  114. else doneCondition.signal();
  115. }
  116. // Runs instead of rest of main() if process is called zerotier-cli or if
  117. // -q is specified as an option.
  118. #ifdef __WINDOWS__
  119. static int main(int argc,_TCHAR* argv[])
  120. #else
  121. static int main(int argc,char **argv)
  122. #endif
  123. {
  124. if (argc <= 1) {
  125. printHelp(stdout,argv[0]);
  126. return -1;
  127. }
  128. std::string authToken;
  129. std::string command;
  130. bool pastSwitches = false;
  131. unsigned int controlPort = 0;
  132. for(int i=1;i<argc;++i) {
  133. if ((argv[i][0] == '-')&&(!pastSwitches)) {
  134. if (strlen(argv[i]) <= 1) {
  135. printHelp(stdout,argv[0]);
  136. return -1;
  137. }
  138. switch(argv[i][1]) {
  139. case 'q': // does nothing, for invocation without binary path name aliasing
  140. if (argv[i][2]) {
  141. printHelp(argv[0],stderr);
  142. return 0;
  143. }
  144. break;
  145. case 'c':
  146. controlPort = Utils::strToUInt(argv[i] + 2);
  147. break;
  148. case 't':
  149. authToken.assign(argv[i] + 2);
  150. break;
  151. case 'T':
  152. if (!Utils::readFile(argv[i] + 2,authToken)) {
  153. fprintf(stdout,"FATAL ERROR: unable to read token from '%s'"ZT_EOL_S,argv[i] + 2);
  154. return -2;
  155. }
  156. break;
  157. case 'h':
  158. printHelp(stdout,argv[0]);
  159. return 0;
  160. default:
  161. return -1;
  162. }
  163. } else {
  164. pastSwitches = true;
  165. if (command.length())
  166. command.push_back(' ');
  167. command.append(argv[i]);
  168. }
  169. }
  170. if (!command.length()) {
  171. printHelp(stdout,argv[0]);
  172. return -1;
  173. }
  174. if (!authToken.length()) {
  175. if (!Utils::readFile(Node::LocalClient::authTokenDefaultUserPath().c_str(),authToken)) {
  176. if (!Utils::readFile(Node::LocalClient::authTokenDefaultSystemPath().c_str(),authToken)) {
  177. fprintf(stdout,"FATAL ERROR: no token specified on command line and could not read '%s' or '%s'"ZT_EOL_S,Node::LocalClient::authTokenDefaultSystemPath().c_str(),Node::LocalClient::authTokenDefaultUserPath().c_str());
  178. return -2;
  179. }
  180. }
  181. }
  182. if (!authToken.length()) {
  183. fprintf(stdout,"FATAL ERROR: could not find auth token"ZT_EOL_S);
  184. return -2;
  185. }
  186. Node::LocalClient client(authToken.c_str(),controlPort,&resultHandler,(void *)0);
  187. client.send(command.c_str());
  188. doneCondition.wait(1000);
  189. if (!numResults) {
  190. fprintf(stdout,"ERROR: no results received. Is ZeroTier One running?"ZT_EOL_S);
  191. return -1;
  192. }
  193. return 0;
  194. }
  195. } // namespace ZeroTierCLI ---------------------------------------------------
  196. namespace ZeroTierIdTool { // ------------------------------------------------
  197. static void printHelp(FILE *out,const char *pn)
  198. {
  199. fprintf(out,"Usage: %s <command> [<args>]"ZT_EOL_S""ZT_EOL_S"Commands:"ZT_EOL_S,pn);
  200. fprintf(out," generate [<identity.secret>] [<identity.public>]"ZT_EOL_S);
  201. fprintf(out," validate <identity.secret/public>"ZT_EOL_S);
  202. fprintf(out," getpublic <identity.secret>"ZT_EOL_S);
  203. fprintf(out," sign <identity.secret> <file>"ZT_EOL_S);
  204. fprintf(out," verify <identity.secret/public> <file> <signature>"ZT_EOL_S);
  205. }
  206. static Identity getIdFromArg(char *arg)
  207. {
  208. Identity id;
  209. if ((strlen(arg) > 32)&&(arg[10] == ':')) { // identity is a literal on the command line
  210. if (id.fromString(arg))
  211. return id;
  212. } else { // identity is to be read from a file
  213. std::string idser;
  214. if (Utils::readFile(arg,idser)) {
  215. if (id.fromString(idser))
  216. return id;
  217. }
  218. }
  219. return Identity();
  220. }
  221. // Runs instead of rest of main() if process is called zerotier-idtool or if
  222. // -i is specified as an option.
  223. #ifdef __WINDOWS__
  224. static int main(int argc,_TCHAR* argv[])
  225. #else
  226. static int main(int argc,char **argv)
  227. #endif
  228. {
  229. if (argc < 2) {
  230. printHelp(stderr,argv[0]);
  231. return -1;
  232. }
  233. if (!strcmp(argv[1],"generate")) {
  234. Identity id;
  235. id.generate();
  236. std::string idser = id.toString(true);
  237. if (argc >= 3) {
  238. if (!Utils::writeFile(argv[2],idser)) {
  239. fprintf(stderr,"Error writing to %s"ZT_EOL_S,argv[2]);
  240. return -1;
  241. } else printf("%s written"ZT_EOL_S,argv[2]);
  242. if (argc >= 4) {
  243. idser = id.toString(false);
  244. if (!Utils::writeFile(argv[3],idser)) {
  245. fprintf(stderr,"Error writing to %s"ZT_EOL_S,argv[3]);
  246. return -1;
  247. } else printf("%s written"ZT_EOL_S,argv[3]);
  248. }
  249. } else printf("%s",idser.c_str());
  250. } else if (!strcmp(argv[1],"validate")) {
  251. if (argc < 3) {
  252. printHelp(stderr,argv[0]);
  253. return -1;
  254. }
  255. Identity id = getIdFromArg(argv[2]);
  256. if (!id) {
  257. fprintf(stderr,"Identity argument invalid or file unreadable: %s"ZT_EOL_S,argv[2]);
  258. return -1;
  259. }
  260. if (!id.locallyValidate()) {
  261. fprintf(stderr,"%s FAILED validation."ZT_EOL_S,argv[2]);
  262. return -1;
  263. } else printf("%s is a valid identity"ZT_EOL_S,argv[2]);
  264. } else if (!strcmp(argv[1],"getpublic")) {
  265. if (argc < 3) {
  266. printHelp(stderr,argv[0]);
  267. return -1;
  268. }
  269. Identity id = getIdFromArg(argv[2]);
  270. if (!id) {
  271. fprintf(stderr,"Identity argument invalid or file unreadable: %s"ZT_EOL_S,argv[2]);
  272. return -1;
  273. }
  274. printf("%s",id.toString(false).c_str());
  275. } else if (!strcmp(argv[1],"sign")) {
  276. if (argc < 4) {
  277. printHelp(stderr,argv[0]);
  278. return -1;
  279. }
  280. Identity id = getIdFromArg(argv[2]);
  281. if (!id) {
  282. fprintf(stderr,"Identity argument invalid or file unreadable: %s"ZT_EOL_S,argv[2]);
  283. return -1;
  284. }
  285. if (!id.hasPrivate()) {
  286. fprintf(stderr,"%s does not contain a private key (must use private to sign)"ZT_EOL_S,argv[2]);
  287. return -1;
  288. }
  289. std::string inf;
  290. if (!Utils::readFile(argv[3],inf)) {
  291. fprintf(stderr,"%s is not readable"ZT_EOL_S,argv[3]);
  292. return -1;
  293. }
  294. C25519::Signature signature = id.sign(inf.data(),(unsigned int)inf.length());
  295. printf("%s",Utils::hex(signature.data,(unsigned int)signature.size()).c_str());
  296. } else if (!strcmp(argv[1],"verify")) {
  297. if (argc < 4) {
  298. printHelp(stderr,argv[0]);
  299. return -1;
  300. }
  301. Identity id = getIdFromArg(argv[2]);
  302. if (!id) {
  303. fprintf(stderr,"Identity argument invalid or file unreadable: %s"ZT_EOL_S,argv[2]);
  304. return -1;
  305. }
  306. std::string inf;
  307. if (!Utils::readFile(argv[3],inf)) {
  308. fprintf(stderr,"%s is not readable"ZT_EOL_S,argv[3]);
  309. return -1;
  310. }
  311. std::string signature(Utils::unhex(argv[4]));
  312. if ((signature.length() > ZT_ADDRESS_LENGTH)&&(id.verify(inf.data(),(unsigned int)inf.length(),signature.data(),(unsigned int)signature.length()))) {
  313. printf("%s signature valid"ZT_EOL_S,argv[3]);
  314. } else {
  315. fprintf(stderr,"%s signature check FAILED"ZT_EOL_S,argv[3]);
  316. return -1;
  317. }
  318. } else {
  319. printHelp(stderr,argv[0]);
  320. return -1;
  321. }
  322. return 0;
  323. }
  324. } // namespace ZeroTierIdTool ------------------------------------------------
  325. #ifdef __UNIX_LIKE__
  326. static void sighandlerHup(int sig)
  327. {
  328. Node *n = node;
  329. if (n)
  330. n->resync();
  331. }
  332. static void sighandlerQuit(int sig)
  333. {
  334. Node *n = node;
  335. if (n)
  336. n->terminate(Node::NODE_NORMAL_TERMINATION,"terminated by signal");
  337. else exit(0);
  338. }
  339. #endif
  340. #ifdef __WINDOWS__
  341. static BOOL WINAPI _handlerRoutine(DWORD dwCtrlType)
  342. {
  343. switch(dwCtrlType) {
  344. case CTRL_C_EVENT:
  345. case CTRL_BREAK_EVENT:
  346. case CTRL_CLOSE_EVENT:
  347. case CTRL_SHUTDOWN_EVENT:
  348. Node *n = node;
  349. if (n)
  350. n->terminate(Node::NODE_NORMAL_TERMINATION,"terminated by signal");
  351. return TRUE;
  352. }
  353. return FALSE;
  354. }
  355. static BOOL IsCurrentUserLocalAdministrator(void)
  356. {
  357. BOOL fReturn = FALSE;
  358. DWORD dwStatus;
  359. DWORD dwAccessMask;
  360. DWORD dwAccessDesired;
  361. DWORD dwACLSize;
  362. DWORD dwStructureSize = sizeof(PRIVILEGE_SET);
  363. PACL pACL = NULL;
  364. PSID psidAdmin = NULL;
  365. HANDLE hToken = NULL;
  366. HANDLE hImpersonationToken = NULL;
  367. PRIVILEGE_SET ps;
  368. GENERIC_MAPPING GenericMapping;
  369. PSECURITY_DESCRIPTOR psdAdmin = NULL;
  370. SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY;
  371. /*
  372. Determine if the current thread is running as a user that is a member
  373. of
  374. the local admins group. To do this, create a security descriptor
  375. that
  376. has a DACL which has an ACE that allows only local aministrators
  377. access.
  378. Then, call AccessCheck with the current thread's token and the
  379. security
  380. descriptor. It will say whether the user could access an object if
  381. it
  382. had that security descriptor. Note: you do not need to actually
  383. create
  384. the object. Just checking access against the security descriptor
  385. alone
  386. will be sufficient.
  387. */
  388. const DWORD ACCESS_READ = 1;
  389. const DWORD ACCESS_WRITE = 2;
  390. __try
  391. {
  392. /*
  393. AccessCheck() requires an impersonation token. We first get a
  394. primary
  395. token and then create a duplicate impersonation token. The
  396. impersonation token is not actually assigned to the thread, but is
  397. used in the call to AccessCheck. Thus, this function itself never
  398. impersonates, but does use the identity of the thread. If the
  399. thread
  400. was impersonating already, this function uses that impersonation
  401. context.
  402. */
  403. if (!OpenThreadToken(GetCurrentThread(), TOKEN_DUPLICATE|TOKEN_QUERY,
  404. TRUE, &hToken))
  405. {
  406. if (GetLastError() != ERROR_NO_TOKEN)
  407. __leave;
  408. if (!OpenProcessToken(GetCurrentProcess(),
  409. TOKEN_DUPLICATE|TOKEN_QUERY, &hToken))
  410. __leave;
  411. }
  412. if (!DuplicateToken (hToken, SecurityImpersonation,
  413. &hImpersonationToken))
  414. __leave;
  415. /*
  416. Create the binary representation of the well-known SID that
  417. represents the local administrators group. Then create the
  418. security
  419. descriptor and DACL with an ACE that allows only local admins
  420. access.
  421. After that, perform the access check. This will determine whether
  422. the current user is a local admin.
  423. */
  424. if (!AllocateAndInitializeSid(&SystemSidAuthority, 2,
  425. SECURITY_BUILTIN_DOMAIN_RID,
  426. DOMAIN_ALIAS_RID_ADMINS,
  427. 0, 0, 0, 0, 0, 0, &psidAdmin))
  428. __leave;
  429. psdAdmin = LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
  430. if (psdAdmin == NULL)
  431. __leave;
  432. if (!InitializeSecurityDescriptor(psdAdmin,
  433. SECURITY_DESCRIPTOR_REVISION))
  434. __leave;
  435. // Compute size needed for the ACL.
  436. dwACLSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) +
  437. GetLengthSid(psidAdmin) - sizeof(DWORD);
  438. pACL = (PACL)LocalAlloc(LPTR, dwACLSize);
  439. if (pACL == NULL)
  440. __leave;
  441. if (!InitializeAcl(pACL, dwACLSize, ACL_REVISION2))
  442. __leave;
  443. dwAccessMask= ACCESS_READ | ACCESS_WRITE;
  444. if (!AddAccessAllowedAce(pACL, ACL_REVISION2, dwAccessMask,
  445. psidAdmin))
  446. __leave;
  447. if (!SetSecurityDescriptorDacl(psdAdmin, TRUE, pACL, FALSE))
  448. __leave;
  449. /*
  450. AccessCheck validates a security descriptor somewhat; set the
  451. group
  452. and owner so that enough of the security descriptor is filled out
  453. to
  454. make AccessCheck happy.
  455. */
  456. SetSecurityDescriptorGroup(psdAdmin, psidAdmin, FALSE);
  457. SetSecurityDescriptorOwner(psdAdmin, psidAdmin, FALSE);
  458. if (!IsValidSecurityDescriptor(psdAdmin))
  459. __leave;
  460. dwAccessDesired = ACCESS_READ;
  461. /*
  462. Initialize GenericMapping structure even though you
  463. do not use generic rights.
  464. */
  465. GenericMapping.GenericRead = ACCESS_READ;
  466. GenericMapping.GenericWrite = ACCESS_WRITE;
  467. GenericMapping.GenericExecute = 0;
  468. GenericMapping.GenericAll = ACCESS_READ | ACCESS_WRITE;
  469. if (!AccessCheck(psdAdmin, hImpersonationToken, dwAccessDesired,
  470. &GenericMapping, &ps, &dwStructureSize, &dwStatus,
  471. &fReturn))
  472. {
  473. fReturn = FALSE;
  474. __leave;
  475. }
  476. }
  477. __finally
  478. {
  479. // Clean up.
  480. if (pACL) LocalFree(pACL);
  481. if (psdAdmin) LocalFree(psdAdmin);
  482. if (psidAdmin) FreeSid(psidAdmin);
  483. if (hImpersonationToken) CloseHandle (hImpersonationToken);
  484. if (hToken) CloseHandle (hToken);
  485. }
  486. return fReturn;
  487. }
  488. #endif // __WINDOWS__
  489. #ifdef __WINDOWS__
  490. int _tmain(int argc, _TCHAR* argv[])
  491. #else
  492. int main(int argc,char **argv)
  493. #endif
  494. {
  495. #ifdef __UNIX_LIKE__
  496. signal(SIGHUP,&sighandlerHup);
  497. signal(SIGPIPE,SIG_IGN);
  498. signal(SIGUSR1,SIG_IGN);
  499. signal(SIGUSR2,SIG_IGN);
  500. signal(SIGALRM,SIG_IGN);
  501. signal(SIGINT,&sighandlerQuit);
  502. signal(SIGTERM,&sighandlerQuit);
  503. signal(SIGQUIT,&sighandlerQuit);
  504. #endif
  505. #ifdef __WINDOWS__
  506. WSADATA wsaData;
  507. WSAStartup(MAKEWORD(2,2),&wsaData);
  508. SetConsoleCtrlHandler(&_handlerRoutine,TRUE);
  509. #endif
  510. if ((strstr(argv[0],"zerotier-cli"))||(strstr(argv[0],"ZEROTIER-CLI")))
  511. return ZeroTierCLI::main(argc,argv);
  512. if ((strstr(argv[0],"zerotier-idtool"))||(strstr(argv[0],"ZEROTIER-IDTOOL")))
  513. return ZeroTierIdTool::main(argc,argv);
  514. const char *homeDir = (const char *)0;
  515. unsigned int port = 0;
  516. unsigned int controlPort = 0;
  517. for(int i=1;i<argc;++i) {
  518. if (argv[i][0] == '-') {
  519. switch(argv[i][1]) {
  520. case 'p':
  521. port = Utils::strToUInt(argv[i] + 2);
  522. if (port > 65535) {
  523. printHelp(argv[0],stderr);
  524. return 1;
  525. }
  526. break;
  527. case 'v':
  528. printf("%s"ZT_EOL_S,Node::versionString());
  529. return 0;
  530. case 'c':
  531. controlPort = Utils::strToUInt(argv[i] + 2);
  532. if (controlPort > 65535) {
  533. printHelp(argv[0],stderr);
  534. return 1;
  535. }
  536. break;
  537. case 'q':
  538. if (argv[i][2]) {
  539. printHelp(argv[0],stderr);
  540. return 0;
  541. } else return ZeroTierCLI::main(argc,argv);
  542. case 'i':
  543. if (argv[i][2]) {
  544. printHelp(argv[0],stderr);
  545. return 0;
  546. } else return ZeroTierIdTool::main(argc,argv);
  547. case 'h':
  548. case '?':
  549. default:
  550. printHelp(argv[0],stderr);
  551. return 0;
  552. }
  553. } else {
  554. if (homeDir) {
  555. printHelp(argv[0],stderr);
  556. return 0;
  557. }
  558. homeDir = argv[i];
  559. break;
  560. }
  561. }
  562. if ((!homeDir)||(strlen(homeDir) == 0))
  563. homeDir = ZT_DEFAULTS.defaultHomePath.c_str();
  564. #ifdef __UNIX_LIKE__
  565. if (getuid()) {
  566. fprintf(stderr,"%s: must be run as root (uid==0)\n",argv[0]);
  567. return 1;
  568. }
  569. mkdir(homeDir,0755); // will fail if it already exists
  570. {
  571. char pidpath[4096];
  572. Utils::snprintf(pidpath,sizeof(pidpath),"%s/zerotier-one.pid",homeDir);
  573. FILE *pf = fopen(pidpath,"w");
  574. if (pf) {
  575. fprintf(pf,"%ld",(long)getpid());
  576. fclose(pf);
  577. }
  578. }
  579. #else
  580. #ifdef __WINDOWS__
  581. if (IsCurrentUserLocalAdministrator() != TRUE) {
  582. fprintf(stderr,"%s: must be run as a local administrator."ZT_EOL_S,argv[0]);
  583. return 1;
  584. }
  585. #endif
  586. #endif
  587. int exitCode = 0;
  588. try {
  589. node = new Node(homeDir,port,controlPort);
  590. switch(node->run()) {
  591. case Node::NODE_RESTART_FOR_UPGRADE: {
  592. const char *upgPath = node->reasonForTermination();
  593. #ifdef __UNIX_LIKE__
  594. // On Unix-type OSes we exec() right into the upgrade. This in turn will
  595. // end with us being re-launched either via the upgrade itself or something
  596. // like OSX's launchd.
  597. if (upgPath) {
  598. Utils::rm((std::string(homeDir)+"/zerotier-one.pid").c_str());
  599. ::execl(upgPath,upgPath,(char *)0);
  600. }
  601. exitCode = 2;
  602. fprintf(stderr,"%s: abnormal termination: unable to execute update at %s\n",argv[0],(upgPath) ? upgPath : "(unknown path)");
  603. #else // not __UNIX_LIKE
  604. #ifdef __WINDOWS__
  605. // On Windows the service checks updates.d and invokes updates if they are
  606. // found there. This only happens after exit code 4. The Windows service
  607. // will listen to stdout as well to catch the filename.
  608. if (upgPath) {
  609. printf("[[[ UPDATE AVAILABLE: \"%s\" ]]]\r\n",upgPath);
  610. exitCode = 4;
  611. } else {
  612. exitCode = 2;
  613. }
  614. #endif // __WINDOWS__
  615. #endif // not __UNIX_LIKE__
  616. } break;
  617. case Node::NODE_UNRECOVERABLE_ERROR: {
  618. exitCode = 3;
  619. const char *termReason = node->reasonForTermination();
  620. fprintf(stderr,"%s: abnormal termination: %s\n",argv[0],(termReason) ? termReason : "(unknown reason)");
  621. } break;
  622. default:
  623. break;
  624. }
  625. delete node;
  626. node = (Node *)0;
  627. } catch ( ... ) {}
  628. #ifdef __UNIX_LIKE__
  629. Utils::rm((std::string(homeDir)+"/zerotier-one.pid").c_str());
  630. #endif
  631. return exitCode;
  632. }