* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <sys/types.h>
-#include <sys/tree.h>
+#include "sys-tree.h"
#include <string.h>
#include <stdio.h>
#include <err.h>
#include <unistd.h>
#include <errno.h>
+#include <pwd.h>
+#include "openbsd.h"
#include "doas.h"
+const char *formerpath;
+
struct envnode {
RB_ENTRY(envnode) node;
const char *key;
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;
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;
}
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, ©->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(©->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);
}