X-Git-Url: https://tinc-vpn.org/git/browse?a=blobdiff_plain;f=src%2Fscript.c;h=e465ab7be90ea352e0514f96026a5daad258e1eb;hb=refs%2Fheads%2F1.1;hp=ceb6a1b4d8d10691c670633ec7a02e6941086cd4;hpb=5cbef906209eb5005f821af8f55a6f5d7e7d060c;p=tinc diff --git a/src/script.c b/src/script.c index ceb6a1b4..2f2c30bf 100644 --- a/src/script.c +++ b/src/script.c @@ -1,7 +1,7 @@ /* script.c -- call an external script Copyright (C) 1999-2005 Ivo Timmermans, - 2000-2017 Guus Sliepen + 2000-2022 Guus Sliepen 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 @@ -26,20 +26,24 @@ #include "names.h" #include "script.h" #include "xalloc.h" +#include "sandbox.h" #ifdef HAVE_PUTENV static void unputenv(const char *p) { const char *e = strchr(p, '='); - if(!e) + + if(!e) { return; - int len = e - p; + } + + ptrdiff_t len = e - p; #ifndef HAVE_UNSETENV -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS // Windows requires putenv("FOO=") to unset %FOO% len++; #endif #endif - char var[len + 1]; + char *var = alloca(len + 1); strncpy(var, p, len); var[len] = 0; #ifdef HAVE_UNSETENV @@ -47,13 +51,15 @@ static void unputenv(const char *p) { #else // We must keep what we putenv() around in memory. // To do this without memory leaks, keep things in a list and reuse if possible. - static list_t list = {}; + static list_t list = {0}; + for list_each(char, data, &list) { if(!strcmp(data, var)) { putenv(data); return; } } + char *data = xstrdup(var); list_insert_tail(&list, data); putenv(data); @@ -64,18 +70,23 @@ static void putenv(const char *p) {} static void unputenv(const char *p) {} #endif -static const int min_env_size; +static const int min_env_size = 10; 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); + 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); + + if(vasprintf(&env->entries[env->n], format, ap) == -1) { + // Assume we are out of memory. + abort(); + } + va_end(ap); } else { env->entries[env->n] = NULL; @@ -88,52 +99,83 @@ 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); + + if(vasprintf(&env->entries[pos], format, ap) == -1) { + abort(); + } + 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); + env->entries = xzalloc(env->size * sizeof(*env->entries)); - if(netname) + if(netname) { environment_add(env, "NETNAME=%s", netname); - if(myname) + } + + if(myname) { environment_add(env, "NAME=%s", myname); - if(device) + } + + if(device) { environment_add(env, "DEVICE=%s", device); - if(iface) + } + + if(iface) { environment_add(env, "INTERFACE=%s", iface); + } + + if(debug_level >= 0) { + environment_add(env, "DEBUG=%d", debug_level); + } } void environment_exit(environment_t *env) { - for(int i = 0; i < env->n; i++) - free(env->entries[i]); + for(int i = 0; i < env->n; i++) { + free_string(env->entries[i]); + } + free(env->entries); } bool execute_script(const char *name, environment_t *env) { + if(!sandbox_can(START_PROCESSES, RIGHT_NOW)) { + return false; + } + char scriptname[PATH_MAX]; char *command; - snprintf(scriptname, sizeof scriptname, "%s" SLASH "%s%s", confbase, name, scriptextension); + snprintf(scriptname, sizeof(scriptname), "%s" SLASH "%s%s", confbase, name, scriptextension); /* First check if there is a script */ -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS + if(!*scriptextension) { - const char *pathext = getenv("PATHEXT") ?: ".COM;.EXE;.BAT;.CMD"; + const char *pathext = getenv("PATHEXT"); + + if(!pathext) { + pathext = ".COM;.EXE;.BAT;.CMD"; + } + size_t pathlen = strlen(pathext); size_t scriptlen = strlen(scriptname); - char fullname[scriptlen + pathlen + 1]; + + const size_t fullnamelen = scriptlen + pathlen + 1; + char *fullname = alloca(fullnamelen); char *ext = fullname + scriptlen; - strncpy(fullname, scriptname, sizeof fullname); + strncpy(fullname, scriptname, fullnamelen); const char *p = pathext; bool found = false; + while(p && *p) { const char *q = strchr(p, ';'); + if(q) { memcpy(ext, p, q - p); ext[q - p] = 0; @@ -141,29 +183,37 @@ bool execute_script(const char *name, environment_t *env) { } else { strncpy(ext, p, pathlen + 1); } - if((found = !access(fullname, F_OK))) + + if((found = !access(fullname, F_OK))) { break; + } + p = q; } - if(!found) + + if(!found) { return true; + } } else #endif - if(access(scriptname, F_OK)) - return true; + if(access(scriptname, F_OK)) { + return true; + } logger(DEBUG_STATUS, LOG_INFO, "Executing script %s", name); /* Set environment */ - for(int i = 0; i < env->n; i++) + for(int i = 0; i < env->n; i++) { putenv(env->entries[i]); + } - if(scriptinterpreter) + if(scriptinterpreter) { xasprintf(&command, "%s \"%s\"", scriptinterpreter, scriptname); - else + } else { xasprintf(&command, "\"%s\"", scriptname); + } int status = system(command); @@ -171,25 +221,28 @@ bool execute_script(const char *name, environment_t *env) { /* Unset environment */ - for(int i = 0; i < env->n; i++) + for(int i = 0; i < env->n; i++) { unputenv(env->entries[i]); + } if(status != -1) { #ifdef WEXITSTATUS + if(WIFEXITED(status)) { /* Child exited by itself */ if(WEXITSTATUS(status)) { logger(DEBUG_ALWAYS, LOG_ERR, "Script %s exited with non-zero status %d", - name, WEXITSTATUS(status)); + name, WEXITSTATUS(status)); return false; } } else if(WIFSIGNALED(status)) { /* Child was killed by a signal */ logger(DEBUG_ALWAYS, LOG_ERR, "Script %s was killed by signal %d (%s)", - name, WTERMSIG(status), strsignal(WTERMSIG(status))); + name, WTERMSIG(status), strsignal(WTERMSIG(status))); return false; } else { /* Something strange happened */ logger(DEBUG_ALWAYS, LOG_ERR, "Script %s terminated abnormally", name); return false; } + #endif } else { logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "system", strerror(errno));