@@ -61,6 +61,8 @@ static void send_msg_chansess_exitstatus(struct Channel * channel,
6161static void send_msg_chansess_exitsignal (struct Channel * channel ,
6262 struct ChanSess * chansess );
6363static void get_termmodes (struct ChanSess * chansess );
64+ static char * create_newvar (const char * param , const char * var );
65+
6466
6567const struct ChanType svrchansess = {
6668 0 , /* sepfds */
@@ -305,6 +307,12 @@ static void closechansess(struct Channel *channel) {
305307 m_free (chansess -> original_command );
306308#endif
307309
310+ if (chansess -> env ) {
311+ char * * p = chansess -> env ;
312+ for (; * p ; free (* p ++ )) {}
313+ m_free (chansess -> env );
314+ }
315+
308316 if (chansess -> tty ) {
309317 /* write the utmp/wtmp login record */
310318 li = chansess_login_alloc (chansess );
@@ -339,6 +347,25 @@ static void closechansess(struct Channel *channel) {
339347 TRACE (("leave closechansess" ))
340348}
341349
350+ static char is_env_allowed (const char * name ) {
351+ char const * p = svr_opts .acceptenv , * q ;
352+ if (!name || name [0 ] == '\0' || strchr (name , '=' )) return 0 ;
353+ /* Comma-separated, LC_ means prefix, TZ= means 1 var. */
354+ if (p ) for (; * p != '\0' ; ) {
355+ for (q = p ; * q != '\0' && * q != ',' ; ++ q ) {}
356+ if (p != q ) {
357+ if (q [-1 ] == '=' ) {
358+ const unsigned size = q - p - 1 ;
359+ if (0 == memcmp (name , p , size ) && name [size ] == '\0' ) return 1 ;
360+ } else {
361+ if (0 == strncmp (name , p , q - p )) return 1 ; /* Prefix match. */
362+ }
363+ }
364+ p = q + 1 ;
365+ }
366+ return 0 ;
367+ }
368+
342369/* Handle requests for a channel. These can be execution requests,
343370 * or x11/authagent forwarding. These are passed to appropriate handlers */
344371static void chansessionrequest (struct Channel * channel ) {
@@ -383,8 +410,25 @@ static void chansessionrequest(struct Channel *channel) {
383410#endif
384411 } else if (strcmp (type , "signal" ) == 0 ) {
385412 ret = sessionsignal (chansess );
413+ } else if (strcmp (type , "env" ) == 0 ) {
414+ char * name = buf_getstring (ses .payload , NULL );
415+ char * value = buf_getstring (ses .payload , NULL );
416+ if (name && value && is_env_allowed (name )) {
417+ char * newvar = create_newvar (name , value );
418+ if (chansess -> env_size + 1 >= chansess -> env_capacity ) {
419+ if (chansess -> env ) {
420+ chansess -> env = m_realloc (chansess -> env , sizeof (* chansess -> env ) * (chansess -> env_capacity <<= 1 ));
421+ } else {
422+ chansess -> env = m_malloc (sizeof (* chansess -> env ) * (chansess -> env_capacity = 16 ));
423+ }
424+ }
425+ chansess -> env [chansess -> env_size ++ ] = newvar ; /* Takes ownership. */
426+ chansess -> env [chansess -> env_size ] = NULL ;
427+ }
428+ m_free (value );
429+ m_free (name );
386430 } else {
387- /* etc, todo "env", "subsystem" */
431+ /* etc */
388432 }
389433
390434out :
@@ -943,6 +987,12 @@ static void execchild(void *user_data) {
943987 }
944988 }
945989
990+ /* Call putenv here first, so "USER" etc. below will override it. */
991+ if (chansess -> env ) {
992+ char * * p = chansess -> env ;
993+ for (; * p ; putenv (* p ++ )) {}
994+ }
995+
946996 /* set env vars */
947997 addnewvar ("USER" , ses .authstate .pw_name );
948998 addnewvar ("LOGNAME" , ses .authstate .pw_name );
@@ -1013,9 +1063,7 @@ void svr_chansessinitialise() {
10131063
10141064}
10151065
1016- /* add a new environment variable, allocating space for the entry */
1017- void addnewvar (const char * param , const char * var ) {
1018-
1066+ static char * create_newvar (const char * param , const char * var ) {
10191067 char * newvar = NULL ;
10201068 int plen , vlen ;
10211069
@@ -1027,8 +1075,13 @@ void addnewvar(const char* param, const char* var) {
10271075 newvar [plen ] = '=' ;
10281076 memcpy (& newvar [plen + 1 ], var , vlen );
10291077 newvar [plen + vlen + 1 ] = '\0' ;
1078+ return newvar ;
1079+ }
1080+
1081+ /* add a new environment variable, allocating space for the entry */
1082+ void addnewvar (const char * param , const char * var ) {
10301083 /* newvar is leaked here, but that's part of putenv()'s semantics */
1031- if (putenv (newvar ) < 0 ) {
1084+ if (putenv (create_newvar ( param , var ) ) < 0 ) {
10321085 dropbear_exit ("environ error" );
10331086 }
10341087}
0 commit comments