X-Git-Url: https://git.librecmc.org/?p=oweals%2Ftinc.git;a=blobdiff_plain;f=src%2Ftincd.c;h=22fb726aaf88b61e733799195d5245b5247654a7;hp=3dab9a01157b5751c14a65f24fc3d82ae94ea94f;hb=1da051a7a2be587f4eb72db419df628f9e68e738;hpb=aca70cd3c3fe787e62c618849e43f67b3870ac20 diff --git a/src/tincd.c b/src/tincd.c index 3dab9a0..22fb726 100644 --- a/src/tincd.c +++ b/src/tincd.c @@ -1,7 +1,7 @@ /* tincd.c -- the main file for tincd Copyright (C) 1998-2005 Ivo Timmermans - 2000-2010 Guus Sliepen + 2000-2017 Guus Sliepen 2008 Max Rijevski 2009 Michael Tokarev 2010 Julien Muchembled @@ -49,7 +49,12 @@ #include #endif +#ifdef HAVE_GETOPT_LONG #include +#else +#include "getopt.h" +#endif + #include "pidfile.h" #include "conf.h" @@ -97,7 +102,7 @@ char *pidfilename = NULL; /* pid file location */ char *logfilename = NULL; /* log file location */ char **g_argv; /* a copy of the cmdline arguments */ -static int status; +static int status = 1; static struct option const long_options[] = { {"config", required_argument, NULL, 'c'}, @@ -114,6 +119,7 @@ static struct option const long_options[] = { {"user", required_argument, NULL, 'U'}, {"logfile", optional_argument, NULL, 4}, {"pidfile", required_argument, NULL, 5}, + {"option", required_argument, NULL, 'o'}, {NULL, 0, NULL, 0} }; @@ -129,20 +135,20 @@ static void usage(bool status) { program_name); else { printf("Usage: %s [option]...\n\n", program_name); - printf(" -c, --config=DIR Read configuration options from DIR.\n" - " -D, --no-detach Don't fork and detach.\n" - " -d, --debug[=LEVEL] Increase debug level or set it to LEVEL.\n" - " -k, --kill[=SIGNAL] Attempt to kill a running tincd and exit.\n" - " -n, --net=NETNAME Connect to net NETNAME.\n" - " -K, --generate-keys[=BITS] Generate public/private RSA keypair.\n" - " -L, --mlock Lock tinc into main memory.\n" - " --logfile[=FILENAME] Write log entries to a logfile.\n" - " --pidfile=FILENAME Write PID to FILENAME.\n" - " -o [HOST.]KEY=VALUE Set global/host configuration value.\n" - " -R, --chroot chroot to NET dir at startup.\n" - " -U, --user=USER setuid to given USER at startup.\n" - " --help Display this help and exit.\n" - " --version Output version information and exit.\n\n"); + printf(" -c, --config=DIR Read configuration options from DIR.\n" + " -D, --no-detach Don't fork and detach.\n" + " -d, --debug[=LEVEL] Increase debug level or set it to LEVEL.\n" + " -k, --kill[=SIGNAL] Attempt to kill a running tincd and exit.\n" + " -n, --net=NETNAME Connect to net NETNAME.\n" + " -K, --generate-keys[=BITS] Generate public/private RSA keypair.\n" + " -L, --mlock Lock tinc into main memory.\n" + " --logfile[=FILENAME] Write log entries to a logfile.\n" + " --pidfile=FILENAME Write PID to FILENAME.\n" + " -o, --option=[HOST.]KEY=VALUE Set global/host configuration value.\n" + " -R, --chroot chroot to NET dir at startup.\n" + " -U, --user=USER setuid to given USER at startup.\n" + " --help Display this help and exit.\n" + " --version Output version information and exit.\n\n"); printf("Report bugs to tinc@tinc-vpn.org.\n"); } } @@ -161,6 +167,11 @@ static bool parse_options(int argc, char **argv) { break; case 'c': /* config file */ + if(confbase) { + fprintf(stderr, "Only one configuration directory can be given.\n"); + usage(true); + return false; + } confbase = xstrdup(optarg); break; @@ -177,7 +188,9 @@ static bool parse_options(int argc, char **argv) { break; #endif - case 'd': /* inc debug level */ + case 'd': /* increase debug level */ + if(!optarg && optind < argc && *argv[optind] != '-') + optarg = argv[optind++]; if(optarg) debug_level = atoi(optarg); else @@ -186,6 +199,8 @@ static bool parse_options(int argc, char **argv) { case 'k': /* kill old tincds */ #ifndef HAVE_MINGW + if(!optarg && optind < argc && *argv[optind] != '-') + optarg = argv[optind++]; if(optarg) { if(!strcasecmp(optarg, "HUP")) kill_tincd = SIGHUP; @@ -203,6 +218,8 @@ static bool parse_options(int argc, char **argv) { kill_tincd = SIGINT; else if(!strcasecmp(optarg, "ALRM")) kill_tincd = SIGALRM; + else if(!strcasecmp(optarg, "ABRT")) + kill_tincd = SIGABRT; else { kill_tincd = atoi(optarg); @@ -222,8 +239,13 @@ static bool parse_options(int argc, char **argv) { case 'n': /* net name given */ /* netname "." is special: a "top-level name" */ - netname = strcmp(optarg, ".") != 0 ? - xstrdup(optarg) : NULL; + if(netname) { + fprintf(stderr, "Only one netname can be given.\n"); + usage(true); + return false; + } + if(optarg && strcmp(optarg, ".")) + netname = xstrdup(optarg); break; case 'o': /* option */ @@ -234,6 +256,8 @@ static bool parse_options(int argc, char **argv) { break; case 'K': /* generate public/private keypair */ + if(!optarg && optind < argc && *argv[optind] != '-') + optarg = argv[optind++]; if(optarg) { generate_keys = atoi(optarg); @@ -271,11 +295,24 @@ static bool parse_options(int argc, char **argv) { case 4: /* write log entries to a file */ use_logfile = true; - if(optarg) + if(!optarg && optind < argc && *argv[optind] != '-') + optarg = argv[optind++]; + if(optarg) { + if(logfilename) { + fprintf(stderr, "Only one logfile can be given.\n"); + usage(true); + return false; + } logfilename = xstrdup(optarg); + } break; case 5: /* write PID to a file */ + if(pidfilename) { + fprintf(stderr, "Only one pidfile can be given.\n"); + usage(true); + return false; + } pidfilename = xstrdup(optarg); break; @@ -288,12 +325,18 @@ static bool parse_options(int argc, char **argv) { } } + if(optind < argc) { + fprintf(stderr, "%s: unrecognized argument '%s'\n", argv[0], argv[optind]); + usage(true); + return false; + } + return true; } /* This function prettyprints the key generation process */ -static void indicator(int a, int b, void *p) { +static int indicator(int a, int b, BN_GENCB *cb) { switch (a) { case 0: fprintf(stderr, "."); @@ -325,43 +368,62 @@ static void indicator(int a, int b, void *p) { default: fprintf(stderr, "?"); } + + return 1; +} + +#ifndef HAVE_BN_GENCB_NEW +BN_GENCB *BN_GENCB_new(void) { + return xmalloc_and_zero(sizeof(BN_GENCB)); } +void BN_GENCB_free(BN_GENCB *cb) { + free(cb); +} +#endif + /* Generate a public/private RSA keypair, and ask for a file to store them in. */ static bool keygen(int bits) { + BIGNUM *e = NULL; RSA *rsa_key; FILE *f; - char *name = NULL; - char *filename; + char *pubname, *privname; + BN_GENCB *cb; + int result; - get_config_string(lookup_config(config_tree, "Name"), &name); + fprintf(stderr, "Generating %d bits keys:\n", bits); - if(name && !check_id(name)) { - fprintf(stderr, "Invalid name for myself!\n"); - return false; - } + cb = BN_GENCB_new(); + if(!cb) + abort(); + BN_GENCB_set(cb, indicator, NULL); - fprintf(stderr, "Generating %d bits keys:\n", bits); - rsa_key = RSA_generate_key(bits, 0x10001, indicator, NULL); + rsa_key = RSA_new(); + BN_hex2bn(&e, "10001"); + if(!rsa_key || !e) + abort(); + + result = RSA_generate_key_ex(rsa_key, bits, e, cb); + + BN_free(e); + BN_GENCB_free(cb); - if(!rsa_key) { + if(!result) { fprintf(stderr, "Error during key generation!\n"); return false; } else fprintf(stderr, "Done.\n"); - xasprintf(&filename, "%s/rsa_key.priv", confbase); - f = ask_and_open(filename, "private RSA key"); + xasprintf(&privname, "%s/rsa_key.priv", confbase); + f = ask_and_open(privname, "private RSA key"); + free(privname); if(!f) return false; - if(disable_old_keys(f)) - fprintf(stderr, "Warning: old key(s) found and disabled.\n"); - #ifdef HAVE_FCHMOD /* Make it unreadable for others. */ fchmod(fileno(f), 0600); @@ -370,27 +432,25 @@ static bool keygen(int bits) { fputc('\n', f); PEM_write_RSAPrivateKey(f, rsa_key, NULL, NULL, 0, NULL, NULL); fclose(f); - free(filename); - if(name) - xasprintf(&filename, "%s/hosts/%s", confbase, name); - else - xasprintf(&filename, "%s/rsa_key.pub", confbase); + char *name = get_name(); + + if(name) { + xasprintf(&pubname, "%s/hosts/%s", confbase, name); + free(name); + } else { + xasprintf(&pubname, "%s/rsa_key.pub", confbase); + } - f = ask_and_open(filename, "public RSA key"); + f = ask_and_open(pubname, "public RSA key"); + free(pubname); if(!f) return false; - if(disable_old_keys(f)) - fprintf(stderr, "Warning: old key(s) found and disabled.\n"); - fputc('\n', f); PEM_write_RSAPublicKey(f, rsa_key); fclose(f); - free(filename); - if(name) - free(name); return true; } @@ -402,7 +462,7 @@ static void make_names(void) { #ifdef HAVE_MINGW HKEY key; char installdir[1024] = ""; - long len = sizeof(installdir); + DWORD len = sizeof(installdir); #endif if(netname) @@ -412,15 +472,15 @@ static void make_names(void) { #ifdef HAVE_MINGW if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\tinc", 0, KEY_READ, &key)) { - if(!RegQueryValueEx(key, NULL, 0, 0, installdir, &len)) { - if(!logfilename) - xasprintf(&logfilename, "%s/log/%s.log", identname); + if(!RegQueryValueEx(key, NULL, 0, 0, (LPBYTE)installdir, &len)) { if(!confbase) { if(netname) xasprintf(&confbase, "%s/%s", installdir, netname); else xasprintf(&confbase, "%s", installdir); } + if(!logfilename) + xasprintf(&logfilename, "%s/tinc.log", confbase); } RegCloseKey(key); if(*installdir) @@ -478,8 +538,11 @@ static bool drop_privs() { "initgroups", strerror(errno)); return false; } +#ifndef __ANDROID__ +// Not supported in android NDK endgrent(); endpwent(); +#endif } if (do_chroot) { tzset(); /* for proper timestamps in logs */ @@ -502,12 +565,12 @@ static bool drop_privs() { } #ifdef HAVE_MINGW -# define setpriority(level) SetPriorityClass(GetCurrentProcess(), level) +# define setpriority(level) !SetPriorityClass(GetCurrentProcess(), (level)) #else # define NORMAL_PRIORITY_CLASS 0 # define BELOW_NORMAL_PRIORITY_CLASS 10 # define HIGH_PRIORITY_CLASS -10 -# define setpriority(level) nice(level) +# define setpriority(level) (setpriority(PRIO_PROCESS, 0, (level))) #endif int main(int argc, char **argv) { @@ -519,9 +582,8 @@ int main(int argc, char **argv) { make_names(); if(show_version) { - printf("%s version %s (built %s %s, protocol %d)\n", PACKAGE, - VERSION, __DATE__, __TIME__, PROT_CURRENT); - printf("Copyright (C) 1998-2010 Ivo Timmermans, Guus Sliepen and others.\n" + printf("%s version %s\n", PACKAGE, VERSION); + printf("Copyright (C) 1998-2017 Ivo Timmermans, Guus Sliepen and others.\n" "See the AUTHORS file for a complete list.\n\n" "tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n" "and you are welcome to redistribute it under certain conditions;\n" @@ -542,6 +604,12 @@ int main(int argc, char **argv) { g_argv = argv; + if(getenv("LISTEN_PID") && atoi(getenv("LISTEN_PID")) == getpid()) + do_detach = false; +#ifdef HAVE_UNSETENV + unsetenv("LISTEN_PID"); +#endif + init_configuration(&config_tree); /* Slllluuuuuuurrrrp! */ @@ -584,6 +652,7 @@ int main2(int argc, char **argv) { InitializeCriticalSection(&mutex); EnterCriticalSection(&mutex); #endif + char *priority = NULL; if(!detach()) return 1; @@ -610,8 +679,6 @@ int main2(int argc, char **argv) { /* Change process priority */ - char *priority = 0; - if(get_config_string(lookup_config(config_tree, "ProcessPriority"), &priority)) { if(!strcasecmp(priority, "Normal")) { if (setpriority(NORMAL_PRIORITY_CLASS) != 0) { @@ -648,7 +715,7 @@ int main2(int argc, char **argv) { /* Shutdown properly. */ ifdebug(CONNECTIONS) - dump_device_stats(); + devops.dump_stats(); close_network_connections(); @@ -659,13 +726,20 @@ end: remove_pid(pidfilename); #endif + free(priority); + EVP_cleanup(); ENGINE_cleanup(); CRYPTO_cleanup_all_ex_data(); +#ifdef HAVE_ERR_REMOVE_STATE + // OpenSSL claims this function was deprecated in 1.0.0, + // but valgrind's leak detector shows you still need to call it to make sure OpenSSL cleans up properly. ERR_remove_state(0); +#endif ERR_free_strings(); exit_configuration(&config_tree); + list_free(cmdline_conf); free_names(); return status;