Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions chansession.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ struct ChanSess {
char * agentfile;
char * agentdir;
#endif

unsigned env_capacity;
unsigned env_size;
char **env;
};

struct ChildPid {
Expand Down
2 changes: 2 additions & 0 deletions runopts.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ typedef struct svr_runopts {
char *pubkey_plugin_options;
#endif

char *acceptenv; /* Comma-separated. */

int pass_on_env;

} svr_runopts;
Expand Down
62 changes: 57 additions & 5 deletions svr-chansession.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ static void send_msg_chansess_exitstatus(const struct Channel * channel,
static void send_msg_chansess_exitsignal(const struct Channel * channel,
const struct ChanSess * chansess);
static void get_termmodes(const struct ChanSess *chansess);
static char *create_newvar(const char *param, const char *var);

const struct ChanType svrchansess = {
"session", /* name */
Expand Down Expand Up @@ -326,6 +327,12 @@ static void cleanupchansess(const struct Channel *channel) {
m_free(chansess->term);
m_free(chansess->original_command);

if (chansess->env) {
char **p = chansess->env;
for (; *p; free(*p++)) {}
m_free(chansess->env);
}

if (chansess->tty) {
/* write the utmp/wtmp login record */
li = chansess_login_alloc(chansess);
Expand Down Expand Up @@ -360,6 +367,25 @@ static void cleanupchansess(const struct Channel *channel) {
TRACE(("leave closechansess"))
}

static char is_env_allowed(const char *name) {
char const *p = svr_opts.acceptenv, *q;
if (!name || name[0] == '\0' || strchr(name, '=')) return 0;
/* Comma-separated, LC_ means prefix, TZ= means 1 var. */
if (p) for (; *p != '\0'; ) {
for (q = p; *q != '\0' && *q != ','; ++q) {}
if (p != q) {
if (q[-1] == '=') {
const unsigned size = q - p - 1;
if (0 == memcmp(name, p, size) && name[size] == '\0') return 1;
} else {
if (0 == strncmp(name, p, q - p)) return 1; /* Prefix match. */
}
}
p = q + 1;
}
return 0;
}

/* Handle requests for a channel. These can be execution requests,
* or x11/authagent forwarding. These are passed to appropriate handlers */
static void chansessionrequest(struct Channel *channel) {
Expand Down Expand Up @@ -404,8 +430,25 @@ static void chansessionrequest(struct Channel *channel) {
#endif
} else if (strcmp(type, "signal") == 0) {
ret = sessionsignal(chansess);
} else if (strcmp(type, "env") == 0) {
char *name = buf_getstring(ses.payload, NULL);
char *value = buf_getstring(ses.payload, NULL);
if (name && value && is_env_allowed(name)) {
char *newvar = create_newvar(name, value);
if (chansess->env_size + 1 >= chansess->env_capacity) {
if (chansess->env) {
chansess->env = m_realloc(chansess->env, sizeof(*chansess->env) * (chansess->env_capacity <<= 1));
} else {
chansess->env = m_malloc(sizeof(*chansess->env) * (chansess->env_capacity = 16));
}
}
chansess->env[chansess->env_size++] = newvar; /* Takes ownership. */
chansess->env[chansess->env_size] = NULL;
}
m_free(value);
m_free(name);
} else {
/* etc, todo "env", "subsystem" */
/* etc */
}

out:
Expand Down Expand Up @@ -1007,6 +1050,12 @@ static void execchild(const void *user_data) {
}
#endif

/* Call putenv here first, so "USER" etc. below will override it. */
if (chansess->env) {
char **p = chansess->env;
for (; *p; putenv(*p++)) {}
}

/* set env vars */
addnewvar("USER", ses.authstate.pw_name);
addnewvar("LOGNAME", ses.authstate.pw_name);
Expand Down Expand Up @@ -1093,9 +1142,7 @@ void svr_chansessinitialise() {

}

/* add a new environment variable, allocating space for the entry */
void addnewvar(const char* param, const char* var) {

static char *create_newvar(const char *param, const char *var) {
char* newvar = NULL;
int plen, vlen;

Expand All @@ -1107,8 +1154,13 @@ void addnewvar(const char* param, const char* var) {
newvar[plen] = '=';
memcpy(&newvar[plen+1], var, vlen);
newvar[plen+vlen+1] = '\0';
return newvar;
}

/* add a new environment variable, allocating space for the entry */
void addnewvar(const char* param, const char* var) {
/* newvar is leaked here, but that's part of putenv()'s semantics */
if (putenv(newvar) < 0) {
if (putenv(create_newvar(param, var)) < 0) {
dropbear_exit("environ error");
}
}
5 changes: 5 additions & 0 deletions svr-runopts.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ static void printhelp(const char * progname) {
"-W <receive_window_buffer> (default %d, larger may be faster, max 10MB)\n"
"-K <keepalive> (0 is never, default %d, in seconds)\n"
"-I <idle_timeout> (0 is never, default %d, in seconds)\n"
"-A env1=,env2 Environment variable names and prefixes to accept\n"
"-z disable QoS\n"
#if DROPBEAR_PLUGIN
"-A <authplugin>[,<options>]\n"
Expand Down Expand Up @@ -166,6 +167,7 @@ void svr_getopts(int argc, char ** argv) {
svr_opts.inetdmode = 0;
svr_opts.portcount = 0;
svr_opts.hostkey = NULL;
svr_opts.acceptenv = NULL;
svr_opts.delay_hostkey = 0;
svr_opts.pidfile = expand_homedir_path(DROPBEAR_PIDFILE);
#if DROPBEAR_SVR_LOCALTCPFWD
Expand Down Expand Up @@ -220,6 +222,9 @@ void svr_getopts(int argc, char ** argv) {
case 'r':
next = &keyfile;
break;
case 'A':
next = &svr_opts.acceptenv;
break;
case 'R':
svr_opts.delay_hostkey = 1;
break;
Expand Down