Put script environment creation/deletion in functions.
authorGuus Sliepen <guus@tinc-vpn.org>
Tue, 21 Mar 2017 20:21:23 +0000 (21:21 +0100)
committerGuus Sliepen <guus@tinc-vpn.org>
Tue, 21 Mar 2017 20:25:19 +0000 (21:25 +0100)
This makes environment handling safer, and also has a single place where
we can add new environment variables that should be present for all
scripts.

12 files changed:
src/graph.c
src/invitation.c
src/logger.c
src/logger.h
src/names.c
src/names.h
src/net_setup.c
src/protocol_auth.c
src/script.c
src/script.h
src/subnet.c
src/tincctl.c

index e570feb..1f1fdb3 100644 (file)
@@ -1,6 +1,6 @@
 /*
     graph.c -- graph algorithms
-    Copyright (C) 2001-2013 Guus Sliepen <guus@tinc-vpn.org>,
+    Copyright (C) 2001-2017 Guus Sliepen <guus@tinc-vpn.org>,
                   2001-2005 Ivo Timmermans
 
     This program is free software; you can redistribute it and/or modify
@@ -247,28 +247,23 @@ static void check_reachability(void) {
                        char *name;
                        char *address;
                        char *port;
-                       char *envp[8] = {NULL};
 
-                       xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
-                       xasprintf(&envp[1], "DEVICE=%s", device ? : "");
-                       xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
-                       xasprintf(&envp[3], "NODE=%s", n->name);
+                       environment_t env;
+                       environment_init(&env);
+                       environment_add(&env, "NODE=%s", n->name);
                        sockaddr2str(&n->address, &address, &port);
-                       xasprintf(&envp[4], "REMOTEADDRESS=%s", address);
-                       xasprintf(&envp[5], "REMOTEPORT=%s", port);
-                       xasprintf(&envp[6], "NAME=%s", myself->name);
+                       environment_add(&env, "REMOTEADDRESS=%s", address);
+                       environment_add(&env, "REMOTEPORT=%s", port);
 
-                       execute_script(n->status.reachable ? "host-up" : "host-down", envp);
+                       execute_script(n->status.reachable ? "host-up" : "host-down", &env);
 
                        xasprintf(&name, n->status.reachable ? "hosts/%s-up" : "hosts/%s-down", n->name);
-                       execute_script(name, envp);
+                       execute_script(name, &env);
 
                        free(name);
                        free(address);
                        free(port);
-
-                       for(int i = 0; i < 7; i++)
-                               free(envp[i]);
+                       environment_exit(&env);
 
                        subnet_update(n, NULL, n->status.reachable);
 
index 08afe78..ff93f9e 100644 (file)
@@ -1,6 +1,6 @@
 /*
     invitation.c -- Create and accept invitations
-    Copyright (C) 2013-2015 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2013-2017 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
@@ -239,7 +239,7 @@ int cmd_invite(int argc, char *argv[]) {
                return 1;
        }
 
-       char *myname = get_my_name(true);
+       myname = get_my_name(true);
        if(!myname)
                return 1;
 
@@ -425,15 +425,13 @@ int cmd_invite(int argc, char *argv[]) {
        xasprintf(&url, "%s/%s%s", address, hash, cookie);
 
        // Call the inviation-created script
-       char *envp[6] = {};
-       xasprintf(&envp[0], "NAME=%s", myname);
-       xasprintf(&envp[1], "NETNAME=%s", netname);
-       xasprintf(&envp[2], "NODE=%s", argv[1]);
-       xasprintf(&envp[3], "INVITATION_FILE=%s", filename);
-       xasprintf(&envp[4], "INVITATION_URL=%s", url);
-       execute_script("invitation-created", envp);
-       for(int i = 0; i < 6 && envp[i]; i++)
-               free(envp[i]);
+       environment_t env;
+       environment_init(&env);
+       environment_add(&env, "NODE=%s", argv[1]);
+       environment_add(&env, "INVITATION_FILE=%s", filename);
+       environment_add(&env, "INVITATION_URL=%s", url);
+       execute_script("invitation-created", &env);
+       environment_exit(&env);
 
        puts(url);
        free(url);
index 6028e3d..4075ea8 100644 (file)
@@ -1,6 +1,6 @@
 /*
     logger.c -- logging code
-    Copyright (C) 2004-2015 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2004-2017 Guus Sliepen <guus@tinc-vpn.org>
                   2004-2005 Ivo Timmermans
 
     This program is free software; you can redistribute it and/or modify
@@ -29,7 +29,7 @@
 #include "process.h"
 #include "sptps.h"
 
-debug_t debug_level = DEBUG_NOTHING;
+int debug_level = DEBUG_NOTHING;
 static logmode_t logmode = LOGMODE_STDERR;
 static pid_t logpid;
 static FILE *logfile = NULL;
index 252497b..f4f46f9 100644 (file)
@@ -1,7 +1,7 @@
 /*
     logger.h -- header file for logger.c
     Copyright (C) 1998-2005 Ivo Timmermans
-                  2000-2012 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2017 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
@@ -67,7 +67,7 @@ enum {
 
 #include <stdbool.h>
 
-extern debug_t debug_level;
+extern int debug_level;
 extern bool logcontrol;
 extern int umbilical;
 extern void openlogger(const char *, logmode_t);
index 6c518f2..0cae28a 100644 (file)
@@ -1,7 +1,7 @@
 /*
     names.c -- generate commonly used (file)names
     Copyright (C) 1998-2005 Ivo Timmermans
-                  2000-2015 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2017 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
@@ -25,6 +25,7 @@
 #include "xalloc.h"
 
 char *netname = NULL;
+char *myname = NULL;
 char *confdir = NULL;           /* base configuration directory */
 char *confbase = NULL;          /* base configuration directory for this instance of tinc */
 bool confbase_given;
@@ -137,6 +138,7 @@ void free_names(void) {
        free(logfilename);
        free(confbase);
        free(confdir);
+       free(myname);
 
        identname = NULL;
        netname = NULL;
@@ -145,4 +147,5 @@ void free_names(void) {
        logfilename = NULL;
        confbase = NULL;
        confdir = NULL;
+       myname = NULL;
 }
index a2395af..e6b99c5 100644 (file)
@@ -1,7 +1,7 @@
 /*
     names.h -- header for names.c
     Copyright (C) 1998-2005 Ivo Timmermans
-                  2000-2015 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2017 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
@@ -25,6 +25,7 @@ extern char *confdir;
 extern char *confbase;
 extern bool confbase_given;
 extern char *netname;
+extern char *myname;
 extern char *identname;
 extern char *unixsocketname;
 extern char *logfilename;
index f5fddd4..6becfbb 100644 (file)
@@ -1,7 +1,7 @@
 /*
     net_setup.c -- Setup.
     Copyright (C) 1998-2005 Ivo Timmermans,
-                  2000-2016 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2017 Guus Sliepen <guus@tinc-vpn.org>
                   2006      Scott Lamb <slamb@slamb.org>
                   2010      Brandon Black <blblack@gmail.com>
 
@@ -48,7 +48,6 @@
 #endif
 
 char *myport;
-static char *myname;
 static io_t device_io;
 devops_t devops;
 bool device_standby = false;
@@ -705,29 +704,17 @@ void device_enable(void) {
 
        /* Run tinc-up script to further initialize the tap interface */
 
-       char *envp[5] = {NULL};
-       xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
-       xasprintf(&envp[1], "DEVICE=%s", device ? : "");
-       xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
-       xasprintf(&envp[3], "NAME=%s", myname);
-
-       execute_script("tinc-up", envp);
-
-       for(int i = 0; i < 4; i++)
-               free(envp[i]);
+       environment_t env;
+       environment_init(&env);
+       execute_script("tinc-up", &env);
+       environment_exit(&env);
 }
 
 void device_disable(void) {
-       char *envp[5] = {NULL};
-       xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
-       xasprintf(&envp[1], "DEVICE=%s", device ? : "");
-       xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
-       xasprintf(&envp[3], "NAME=%s", myname);
-
-       execute_script("tinc-down", envp);
-
-       for(int i = 0; i < 4; i++)
-               free(envp[i]);
+       environment_t env;
+       environment_init(&env);
+       execute_script("tinc-down", &env);
+       environment_exit(&env);
 
        if (devops.disable)
                devops.disable();
@@ -1150,7 +1137,6 @@ void close_network_connections(void) {
 
        exit_control();
 
-       free(myname);
        free(scriptextension);
        free(scriptinterpreter);
 
index d4705bd..31906ba 100644 (file)
@@ -1,7 +1,7 @@
 /*
     protocol_auth.c -- handle the meta-protocol, authentication
     Copyright (C) 1999-2005 Ivo Timmermans,
-                  2000-2016 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2017 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
@@ -180,21 +180,18 @@ static bool finalize_invitation(connection_t *c, const char *data, uint16_t len)
        logger(DEBUG_CONNECTIONS, LOG_INFO, "Key succesfully received from %s (%s)", c->name, c->hostname);
 
        // Call invitation-accepted script
-       char *envp[7] = {NULL};
+       environment_t env;
        char *address, *port;
 
-       xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
-        xasprintf(&envp[1], "DEVICE=%s", device ? : "");
-        xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
-        xasprintf(&envp[3], "NODE=%s", c->name);
+       environment_init(&env);
+        environment_add(&env, "NODE=%s", c->name);
        sockaddr2str(&c->address, &address, &port);
-       xasprintf(&envp[4], "REMOTEADDRESS=%s", address);
-       xasprintf(&envp[5], "NAME=%s", myself->name);
+       environment_add(&env, "REMOTEADDRESS=%s", address);
+       environment_add(&env, "NAME=%s", myself->name);
 
-       execute_script("invitation-accepted", envp);
+       execute_script("invitation-accepted", &env);
 
-       for(int i = 0; envp[i] && i < 7; i++)
-               free(envp[i]);
+       environment_exit(&env);
 
        sptps_send_record(&c->sptps, 2, data, 0);
        return true;
index d4db889..ceb6a1b 100644 (file)
@@ -1,7 +1,7 @@
 /*
     script.c -- call an external script
     Copyright (C) 1999-2005 Ivo Timmermans,
-                  2000-2015 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2017 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
@@ -21,6 +21,7 @@
 #include "system.h"
 
 #include "conf.h"
+#include "device.h"
 #include "logger.h"
 #include "names.h"
 #include "script.h"
@@ -63,7 +64,56 @@ static void putenv(const char *p) {}
 static void unputenv(const char *p) {}
 #endif
 
-bool execute_script(const char *name, char **envp) {
+static const int min_env_size;
+
+int environment_add(environment_t *env, const char *format, ...) {
+       if(env->n >= env->size) {
+               env->size = env->n ? env->n * 2 : min_env_size;
+               env->entries = xrealloc(env->entries, env->size * sizeof *env->entries);
+       }
+
+       if(format) {
+               va_list ap;
+               va_start(ap, format);
+               vasprintf(&env->entries[env->n], format, ap);
+               va_end(ap);
+       } else {
+               env->entries[env->n] = NULL;
+       }
+
+       return env->n++;
+}
+
+void environment_update(environment_t *env, int pos, const char *format, ...) {
+       free(env->entries[pos]);
+       va_list ap;
+       va_start(ap, format);
+       vasprintf(&env->entries[pos], format, ap);
+       va_end(ap);
+}
+
+void environment_init(environment_t *env) {
+       env->n = 0;
+       env->size = min_env_size;
+       env->entries = 0; //xzalloc(env->size * sizeof *env->entries);
+
+       if(netname)
+               environment_add(env, "NETNAME=%s", netname);
+       if(myname)
+               environment_add(env, "NAME=%s", myname);
+       if(device)
+               environment_add(env, "DEVICE=%s", device);
+       if(iface)
+               environment_add(env, "INTERFACE=%s", iface);
+}
+
+void environment_exit(environment_t *env) {
+       for(int i = 0; i < env->n; i++)
+               free(env->entries[i]);
+       free(env->entries);
+}
+
+bool execute_script(const char *name, environment_t *env) {
        char scriptname[PATH_MAX];
        char *command;
 
@@ -107,8 +157,8 @@ bool execute_script(const char *name, char **envp) {
 
        /* Set environment */
 
-       for(int i = 0; envp[i]; i++)
-               putenv(envp[i]);
+       for(int i = 0; i < env->n; i++)
+               putenv(env->entries[i]);
 
        if(scriptinterpreter)
                xasprintf(&command, "%s \"%s\"", scriptinterpreter, scriptname);
@@ -121,8 +171,8 @@ bool execute_script(const char *name, char **envp) {
 
        /* Unset environment */
 
-       for(int i = 0; envp[i]; i++)
-               unputenv(envp[i]);
+       for(int i = 0; i < env->n; i++)
+               unputenv(env->entries[i]);
 
        if(status != -1) {
 #ifdef WEXITSTATUS
index 446a3b9..2e26418 100644 (file)
@@ -1,7 +1,7 @@
 /*
     script.h -- header file for script.c
     Copyright (C) 1999-2005 Ivo Timmermans,
-                  2000-2013 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2017 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
 #ifndef __TINC_SCRIPT_H__
 #define __TINC_SCRIPT_H__
 
-extern bool execute_script(const char *, char **);
+typedef struct environment {
+       int n;
+       int size;
+       char **entries;
+} environment_t;
+
+extern int environment_add(environment_t *env, const char *format, ...);
+extern int environment_placeholder(environment_t *env);
+extern void environment_update(environment_t *env, int pos, const char *format, ...);
+extern void environment_init(environment_t *env);
+extern void environment_exit(environment_t *env);
+
+extern bool execute_script(const char *name, environment_t *env);
 
 #endif /* __TINC_SCRIPT_H__ */
index 090a62b..3d055b6 100644 (file)
@@ -1,6 +1,6 @@
 /*
     subnet.c -- handle subnet lookups and lists
-    Copyright (C) 2000-2013 Guus Sliepen <guus@tinc-vpn.org>,
+    Copyright (C) 2000-2017 Guus Sliepen <guus@tinc-vpn.org>,
                   2000-2005 Ivo Timmermans
 
     This program is free software; you can redistribute it and/or modify
@@ -206,22 +206,20 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
 
        // Prepare environment variables to be passed to the script
 
-       char *envp[10] = {NULL};
-       int n = 0;
-       xasprintf(&envp[n++], "NETNAME=%s", netname ? : "");
-       xasprintf(&envp[n++], "DEVICE=%s", device ? : "");
-       xasprintf(&envp[n++], "INTERFACE=%s", iface ? : "");
-       xasprintf(&envp[n++], "NODE=%s", owner->name);
+       environment_t env;
+       environment_init(&env);
+       environment_add(&env, "NODE=%s", owner->name);
 
        if(owner != myself) {
                sockaddr2str(&owner->address, &address, &port);
-               xasprintf(&envp[n++], "REMOTEADDRESS=%s", address);
-               xasprintf(&envp[n++], "REMOTEPORT=%s", port);
+               environment_add(&env, "REMOTEADDRESS=%s", address);
+               environment_add(&env, "REMOTEPORT=%s", port);
                free(port);
                free(address);
        }
 
-       xasprintf(&envp[n++], "NAME=%s", myself->name);
+       int env_subnet = environment_add(&env, NULL);
+       int env_weight = environment_add(&env, NULL);
 
        name = up ? "subnet-up" : "subnet-down";
 
@@ -238,12 +236,10 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
                                weight = empty;
 
                        // Prepare the SUBNET and WEIGHT variables
-                       free(envp[n]);
-                       free(envp[n + 1]);
-                       xasprintf(&envp[n], "SUBNET=%s", netstr);
-                       xasprintf(&envp[n + 1], "WEIGHT=%s", weight);
+                       environment_update(&env, env_subnet, "SUBNET=%s", netstr);
+                       environment_update(&env, env_weight, "WEIGHT=%s", weight);
 
-                       execute_script(name, envp);
+                       execute_script(name, &env);
                }
        } else {
                if(net2str(netstr, sizeof netstr, subnet)) {
@@ -255,15 +251,14 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
                                weight = empty;
 
                        // Prepare the SUBNET and WEIGHT variables
-                       xasprintf(&envp[n], "SUBNET=%s", netstr);
-                       xasprintf(&envp[n + 1], "WEIGHT=%s", weight);
+                       environment_update(&env, env_subnet, "SUBNET=%s", netstr);
+                       environment_update(&env, env_weight, "WEIGHT=%s", weight);
 
-                       execute_script(name, envp);
+                       execute_script(name, &env);
                }
        }
 
-       for(int i = 0; envp[i] && i < 9; i++)
-               free(envp[i]);
+       environment_exit(&env);
 }
 
 bool dump_subnets(connection_t *c) {
index 5067ded..2db9f23 100644 (file)
@@ -74,6 +74,9 @@ bool netnamegiven = false;
 char *scriptinterpreter = NULL;
 char *scriptextension = "";
 static char *prompt;
+char *device = NULL;
+char *iface = NULL;
+int debug_level = -1;
 
 static struct option const long_options[] = {
        {"batch", no_argument, NULL, 'b'},
@@ -89,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-2016 Ivo Timmermans, Guus Sliepen and others.\n"
+       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"