]> git.armaanb.net Git - opendoas.git/blobdiff - env.c
Handle empty argv
[opendoas.git] / env.c
diff --git a/env.c b/env.c
index f25d21f7abc9f0d8b73ca1f2f4ccde926fcfcc2a..e2286fc83b0232425f67a8cda355ef1453f7739f 100644 (file)
--- a/env.c
+++ b/env.c
@@ -15,6 +15,8 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include "config.h"
+
 #include <sys/types.h>
 #include "sys-tree.h"
 
 #include <err.h>
 #include <unistd.h>
 #include <errno.h>
+#include <pwd.h>
 
+#include "openbsd.h"
 #include "doas.h"
-#include "includes.h"
+
+const char *formerpath;
 
 struct envnode {
        RB_ENTRY(envnode) node;
@@ -39,20 +44,56 @@ struct env {
        u_int count;
 };
 
-int
+static void fillenv(struct env *env, const char **envlist);
+
+static int
 envcmp(struct envnode *a, struct envnode *b)
 {
        return strcmp(a->key, b->key);
 }
 RB_GENERATE_STATIC(envtree, envnode, node, envcmp)
 
-struct env *createenv(char **);
-struct env *filterenv(struct env *, struct rule *);
-char **flattenenv(struct env *);
+static struct envnode *
+createnode(const char *key, const char *value)
+{
+       struct envnode *node;
+
+       node = malloc(sizeof(*node));
+       if (!node)
+               err(1, NULL);
+       node->key = strdup(key);
+       node->value = strdup(value);
+       if (!node->key || !node->value)
+               err(1, NULL);
+       return node;
+}
+
+static void
+freenode(struct envnode *node)
+{
+       free((char *)node->key);
+       free((char *)node->value);
+       free(node);
+}
+
+static void
+addnode(struct env *env, const char *key, const char *value)
+{
+       struct envnode *node;
 
-struct env *
-createenv(char **envp)
+       node = createnode(key, value);
+       RB_INSERT(envtree, &env->root, node);
+       env->count++;
+}
+
+static struct env *
+createenv(const struct rule *rule, const struct passwd *mypw,
+    const struct passwd *targpw)
 {
+       static const char *copyset[] = {
+               "DISPLAY", "TERM",
+               NULL
+       };
        struct env *env;
        u_int i;
 
@@ -62,34 +103,49 @@ createenv(char **envp)
        RB_INIT(&env->root);
        env->count = 0;
 
-       for (i = 0; envp[i] != NULL; i++) {
-               struct envnode *node;
-               const char *e, *eq;
-
-               e = envp[i];
-
-               if ((eq = strchr(e, '=')) == NULL || eq == e)
-                       continue;
-               node = malloc(sizeof(*node));
-               if (!node)
-                       err(1, NULL);
-               node->key = strndup(envp[i], eq - e);
-               node->value = strdup(eq + 1);
-               if (!node->key || !node->value)
-                       err(1, NULL);
-               if (RB_FIND(envtree, &env->root, node)) {
-                       free((char *)node->key);
-                       free((char *)node->value);
-                       free(node);
-               } else {
-                       RB_INSERT(envtree, &env->root, node);
-                       env->count++;
+       addnode(env, "DOAS_USER", mypw->pw_name);
+       addnode(env, "HOME", targpw->pw_dir);
+       addnode(env, "LOGNAME", targpw->pw_name);
+       addnode(env, "PATH", getenv("PATH"));
+       addnode(env, "SHELL", targpw->pw_shell);
+       addnode(env, "USER", targpw->pw_name);
+
+       fillenv(env, copyset);
+
+       if (rule->options & KEEPENV) {
+               extern char **environ;
+
+               for (i = 0; environ[i] != NULL; i++) {
+                       struct envnode *node;
+                       const char *e, *eq;
+                       size_t len;
+                       char keybuf[1024];
+
+                       e = environ[i];
+
+                       /* ignore invalid or overlong names */
+                       if ((eq = strchr(e, '=')) == NULL || eq == e)
+                               continue;
+                       len = eq - e;
+                       if (len > sizeof(keybuf) - 1)
+                               continue;
+                       memcpy(keybuf, e, len);
+                       keybuf[len] = '\0';
+
+                       node = createnode(keybuf, eq + 1);
+                       if (RB_INSERT(envtree, &env->root, node)) {
+                               /* ignore any later duplicates */
+                               freenode(node);
+                       } else {
+                               env->count++;
+                       }
                }
        }
+
        return env;
 }
 
-char **
+static char **
 flattenenv(struct env *env)
 {
        char **envp;
@@ -110,72 +166,73 @@ flattenenv(struct env *env)
 }
 
 static void
-copyenv(struct env *orig, struct env *copy, const char **envlist)
+fillenv(struct env *env, const char **envlist)
 {
        struct envnode *node, key;
+       const char *e, *eq;
+       const char *val;
+       char name[1024];
        u_int i;
+       size_t len;
 
        for (i = 0; envlist[i]; i++) {
-               key.key = envlist[i];
-               if ((node = RB_FIND(envtree, &orig->root, &key))) {
-                       RB_REMOVE(envtree, &orig->root, node);
-                       orig->count--;
-                       RB_INSERT(envtree, &copy->root, node);
-                       copy->count++;
+               e = envlist[i];
+
+               /* parse out env name */
+               if ((eq = strchr(e, '=')) == NULL)
+                       len = strlen(e);
+               else
+                       len = eq - e;
+               if (len > sizeof(name) - 1)
+                       continue;
+               memcpy(name, e, len);
+               name[len] = '\0';
+
+               /* delete previous copies */
+               key.key = name;
+               if (*name == '-')
+                       key.key = name + 1;
+               if ((node = RB_FIND(envtree, &env->root, &key))) {
+                       RB_REMOVE(envtree, &env->root, node);
+                       freenode(node);
+                       env->count--;
                }
-       }
-}
-
-struct env *
-filterenv(struct env *orig, struct rule *rule)
-{
-       const char *safeset[] = {
-               "DISPLAY", "HOME", "LOGNAME", "MAIL",
-               "PATH", "TERM", "USER", "USERNAME",
-               NULL
-       };
-       const char *badset[] = {
-               "ENV",
-               NULL
-       };
-       struct env *copy;
-       struct envnode *node, key;
-       u_int i;
+               if (*name == '-')
+                       continue;
 
-       if ((rule->options & KEEPENV) && !rule->envlist) {
-               for (i = 0; badset[i]; i++) {
-                       key.key = badset[i];
-                       if ((node = RB_FIND(envtree, &orig->root, &key))) {
-                               RB_REMOVE(envtree, &orig->root, node);
-                               free((char *)node->key);
-                               free((char *)node->value);
-                               free(node);
-                               orig->count--;
+               /* assign value or inherit from environ */
+               if (eq) {
+                       val = eq + 1;
+                       if (*val == '$') {
+                               if (strcmp(val + 1, "PATH") == 0)
+                                       val = formerpath;
+                               else
+                                       val = getenv(val + 1);
                        }
+               } else {
+                       if (strcmp(name, "PATH") == 0)
+                               val = formerpath;
+                       else
+                               val = getenv(name);
+               }
+               /* at last, we have something to insert */
+               if (val) {
+                       node = createnode(name, val);
+                       RB_INSERT(envtree, &env->root, node);
+                       env->count++;
                }
-               return orig;
        }
-
-       copy = malloc(sizeof(*copy));
-       if (!copy)
-               err(1, NULL);
-       RB_INIT(&copy->root);
-       copy->count = 0;
-
-       if (rule->envlist)
-               copyenv(orig, copy, rule->envlist);
-       copyenv(orig, copy, safeset);
-
-       return copy;
 }
 
 char **
-prepenv(struct rule *rule)
+prepenv(const struct rule *rule, const struct passwd *mypw,
+    const struct passwd *targpw)
 {
-       extern char **environ;
        struct env *env;
-       
-       env = createenv(environ);
-       env = filterenv(env, rule);
+
+       env = createenv(rule, mypw, targpw);
+       if (rule->envlist)
+               fillenv(env, rule->envlist);
+
        return flattenenv(env);
 }