Fix warnings from the Clang static analyzer.
[tinc] / src / tincctl.c
index 5ba7161..4f6660a 100644 (file)
@@ -1,6 +1,6 @@
 /*
     tincctl.c -- Controlling a running tincd
-    Copyright (C) 2007-2017 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2007-2018 Guus Sliepen <guus@tinc-vpn.org>
 
     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
@@ -92,7 +92,7 @@ static struct option const long_options[] = {
 static void version(void) {
        printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE,
               BUILD_VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
-       printf("Copyright (C) 1998-2017 Ivo Timmermans, Guus Sliepen and others.\n"
+       printf("Copyright (C) 1998-2018 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"
@@ -355,6 +355,8 @@ static FILE *ask_and_open(const char *filename, const char *what, const char *mo
        char buf[PATH_MAX];
        char buf2[PATH_MAX];
 
+ask_filename:
+
        /* Check stdin and stdout */
        if(ask && tty) {
                /* Ask for a file and/or directory name. */
@@ -385,7 +387,17 @@ static FILE *ask_and_open(const char *filename, const char *what, const char *mo
 #endif
                /* The directory is a relative path or a filename. */
                getcwd(directory, sizeof(directory));
-               snprintf(buf2, sizeof(buf2), "%s" SLASH "%s", directory, filename);
+
+               if(snprintf(buf2, sizeof(buf2), "%s" SLASH "%s", directory, filename) >= sizeof(buf2)) {
+                       fprintf(stderr, "Filename too long: %s" SLASH "%s\n", directory, filename);
+
+                       if(ask && tty) {
+                               goto ask_filename;
+                       } else {
+                               return NULL;
+                       }
+               }
+
                filename = buf2;
        }
 
@@ -825,6 +837,8 @@ bool connect_tincd(bool verbose) {
 
        strncpy(sa.sun_path, unixsocketname, sizeof(sa.sun_path));
 
+       sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
+
        fd = socket(AF_UNIX, SOCK_STREAM, 0);
 
        if(fd < 0) {
@@ -902,6 +916,8 @@ bool connect_tincd(bool verbose) {
        setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&one, sizeof(one));
 #endif
 
+       sendline(fd, "%d ^%s %d", ID, controlcookie, TINC_CTL_VERSION_CURRENT);
+
        char data[4096];
        int version;
 
@@ -915,8 +931,6 @@ bool connect_tincd(bool verbose) {
                return false;
        }
 
-       sendline(fd, "%d ^%s %d", ID, controlcookie, TINC_CTL_VERSION_CURRENT);
-
        if(!recvline(fd, line, sizeof(line)) || sscanf(line, "%d %d %d", &code, &version, &pid) != 3 || code != 4 || version != TINC_CTL_VERSION_CURRENT) {
                if(verbose) {
                        fprintf(stderr, "Could not fully establish control socket connection\n");
@@ -1161,7 +1175,12 @@ static int dump_invitations(void) {
                }
 
                char fname[PATH_MAX];
-               snprintf(fname, sizeof(fname), "%s" SLASH "%s", dname, ent->d_name);
+
+               if(snprintf(fname, sizeof(fname), "%s" SLASH "%s", dname, ent->d_name) >= sizeof(fname)) {
+                       fprintf(stderr, "Filename too long: %s" SLASH "%s\n", dname, ent->d_name);
+                       continue;
+               }
+
                FILE *f = fopen(fname, "r");
 
                if(!f) {
@@ -1298,12 +1317,14 @@ static int cmd_dump(int argc, char *argv[]) {
                unsigned int options, status_int;
                node_status_t status;
                long int last_state_change;
+               int udp_ping_rtt;
+               uint64_t in_packets, in_bytes, out_packets, out_bytes;
 
                switch(req) {
                case REQ_DUMP_NODES: {
-                       int n = sscanf(line, "%*d %*d %4095s %4095s %4095s port %4095s %d %d %d %d %x %x %4095s %4095s %d %hd %hd %hd %ld", node, id, host, port, &cipher, &digest, &maclength, &compression, &options, &status_int, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change);
+                       int n = sscanf(line, "%*d %*d %4095s %4095s %4095s port %4095s %d %d %d %d %x %x %4095s %4095s %d %hd %hd %hd %ld %d %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64, node, id, host, port, &cipher, &digest, &maclength, &compression, &options, &status_int, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change, &udp_ping_rtt, &in_packets, &in_bytes, &out_packets, &out_bytes);
 
-                       if(n != 17) {
+                       if(n != 22) {
                                fprintf(stderr, "Unable to parse node dump from tincd: %s\n", line);
                                return 1;
                        }
@@ -1331,8 +1352,14 @@ static int cmd_dump(int argc, char *argv[]) {
                                        continue;
                                }
 
-                               printf("%s id %s at %s port %s cipher %d digest %d maclength %d compression %d options %x status %04x nexthop %s via %s distance %d pmtu %d (min %d max %d)\n",
-                                      node, id, host, port, cipher, digest, maclength, compression, options, status_int, nexthop, via, distance, pmtu, minmtu, maxmtu);
+                               printf("%s id %s at %s port %s cipher %d digest %d maclength %d compression %d options %x status %04x nexthop %s via %s distance %d pmtu %d (min %d max %d) rx %"PRIu64" %"PRIu64" tx %"PRIu64" %"PRIu64,
+                                      node, id, host, port, cipher, digest, maclength, compression, options, status_int, nexthop, via, distance, pmtu, minmtu, maxmtu, in_packets, in_bytes, out_packets, out_bytes);
+
+                               if(udp_ping_rtt != -1) {
+                                       printf(" rtt %d.%03d", udp_ping_rtt / 1000, udp_ping_rtt % 1000);
+                               }
+
+                               printf("\n");
                        }
                }
                break;
@@ -1695,6 +1722,7 @@ const var_t variables[] = {
        {"Ed25519PrivateKeyFile", VAR_SERVER},
        {"ExperimentalProtocol", VAR_SERVER},
        {"Forwarding", VAR_SERVER},
+       {"FWMark", VAR_SERVER},
        {"GraphDumpFile", VAR_SERVER | VAR_OBSOLETE},
        {"Hostnames", VAR_SERVER},
        {"IffOneQueue", VAR_SERVER},
@@ -1921,7 +1949,11 @@ static int cmd_config(int argc, char *argv[]) {
        FILE *tf = NULL;
 
        if(action >= -1) {
-               snprintf(tmpfile, sizeof(tmpfile), "%s.config.tmp", filename);
+               if(snprintf(tmpfile, sizeof(tmpfile), "%s.config.tmp", filename) >= sizeof(tmpfile)) {
+                       fprintf(stderr, "Filename too long: %s.config.tmp\n", filename);
+                       return 1;
+               }
+
                tf = fopen(tmpfile, "w");
 
                if(!tf) {
@@ -2119,7 +2151,7 @@ static bool try_bind(int port) {
        return success;
 }
 
-int check_port(char *name) {
+int check_port(const char *name) {
        if(try_bind(655)) {
                return 655;
        }
@@ -2528,7 +2560,10 @@ static int cmd_import(int argc, char *argv[]) {
                                fclose(out);
                        }
 
-                       snprintf(filename, sizeof(filename), "%s" SLASH "%s", hosts_dir, name);
+                       if(snprintf(filename, sizeof(filename), "%s" SLASH "%s", hosts_dir, name) >= sizeof(filename)) {
+                               fprintf(stderr, "Filename too long: %s" SLASH "%s\n", hosts_dir, name);
+                               return 1;
+                       }
 
                        if(!force && !access(filename, F_OK)) {
                                fprintf(stderr, "Host configuration file %s already exists, skipping.\n", filename);
@@ -3140,10 +3175,7 @@ static int cmd_shell(int argc, char *argv[]) {
                        free(line);
                        rl_basic_word_break_characters = "\t\n ";
                        line = readline(prompt);
-
-                       if(line) {
-                               copy = xstrdup(line);
-                       }
+                       copy = line ? xstrdup(line) : NULL;
                } else {
                        line = fgets(buf, sizeof(buf), stdin);
                }
@@ -3189,6 +3221,9 @@ static int cmd_shell(int argc, char *argv[]) {
                }
 
                if(!strcasecmp(nargv[argc], "exit") || !strcasecmp(nargv[argc], "quit")) {
+#ifdef HAVE_READLINE
+                       free(copy);
+#endif
                        free(nargv);
                        return result;
                }
@@ -3217,6 +3252,9 @@ static int cmd_shell(int argc, char *argv[]) {
                }
        }
 
+#ifdef HAVE_READLINE
+       free(copy);
+#endif
        free(nargv);
 
        if(tty) {
@@ -3255,7 +3293,7 @@ int main(int argc, char *argv[]) {
        static struct WSAData wsa_state;
 
        if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
-               fprintf(stderr, "System call `%s' failed: %s", "WSAStartup", winerror(GetLastError()));
+               fprintf(stderr, "System call `%s' failed: %s\n", "WSAStartup", winerror(GetLastError()));
                return false;
        }