[fuchsia] fix environment variable setup

Bug: US-562 #comment environment variables are set
Bug: CONN-18 #comment ssh now sets SSH_ vars that contain connection (and scope) info. which may be used to address local interface selection challenges.
Change-Id: I8c518ff39a3e0734210e271648516a0c85cea0b1
diff --git a/fuchsia/config.h b/fuchsia/config.h
index 5d3da60..3bb476b 100644
--- a/fuchsia/config.h
+++ b/fuchsia/config.h
@@ -1654,7 +1654,7 @@
 /* #undef UNIXWARE_LONG_PASSWORDS */
 
 /* Specify default $PATH */
-#define USER_PATH "/pkg/bin:/boot/bin:/system/bin"
+#define USER_PATH "/bin:/pkg/bin:/boot/bin:/system/bin"
 
 /* Define this if you want to use libkafs' AFS support */
 /* #undef USE_AFS */
diff --git a/fuchsia/fuchsia-compat.c b/fuchsia/fuchsia-compat.c
index e41c20d..d6e56c1 100644
--- a/fuchsia/fuchsia-compat.c
+++ b/fuchsia/fuchsia-compat.c
@@ -311,7 +311,8 @@
 	return pip[1];
 }
 
-pid_t fuchsia_launch_child(const char* command, int in, int out, int err, bool transform) {
+// Note: **env is consumed by this function and will be freed.
+pid_t fuchsia_launch_child(const char* command, char** env, int in, int out, int err, bool transform) {
 	const char* argv[ARGV_MAX];
 	int argc = 1;
 	argv[0] = "/boot/bin/sh";
@@ -374,8 +375,15 @@
 	zx_handle_t proc = 0;
 	char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
 
-	uint32_t flags = FDIO_SPAWN_CLONE_ENVIRON | FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_NAMESPACE;
-	status = fdio_spawn_etc(ZX_HANDLE_INVALID, flags, argv[0], argv, NULL, 4, actions, &proc, err_msg);
+	uint32_t flags = FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_NAMESPACE;
+	status = fdio_spawn_etc(ZX_HANDLE_INVALID, flags, argv[0], argv, (const char* const *)env, 4, actions, &proc, err_msg);
+	// env is constructed in session.c by child_set_env that always printf's new values and callocs the list pointer.
+	// walk each member, freeing them, then free the list.
+	char **envf = env;
+	while(*envf != NULL) {
+		free(*envf++);
+	}
+	free(env);
 
 	if (status < 0) {
 		fprintf(stderr, "error from fdio_spawn_etc: %s\n", err_msg);
diff --git a/fuchsia/fuchsia-compat.h b/fuchsia/fuchsia-compat.h
index 5302c0f..3b0f6bb 100644
--- a/fuchsia/fuchsia-compat.h
+++ b/fuchsia/fuchsia-compat.h
@@ -10,7 +10,9 @@
 void fuchsia_init_async(void);
 
 int chroot(const char *path);
-int fuchsia_launch_child(const char *command, int in, int out, int err, bool transform);
+
+// Note: char** env is consumed by this function and will be freed.
+int fuchsia_launch_child(const char* command, char** env, int in, int out, int err, bool transform);
 
 /* This implements the subset of select() functionality used by openssh */
 /* Uses void* instead of fd_set* for the read/write fd sets since this compat header is included in
diff --git a/session.c b/session.c
index 14ea1cc..8a2c20f 100644
--- a/session.c
+++ b/session.c
@@ -384,6 +384,17 @@
 }
 
 #define USE_PIPES 1
+
+// Fuchsia change, this function is defined below (and left there in order to ease merges from upstream).
+// This function is made available for the Fuchsia port, as we do not fork (and
+// later run do_setup_env in the child), instead we must use this function to
+// generate the new environment and pass it to fuchsia_launch_child.
+// This function allocates the char**, which is a nullptr terminated list of environment variables.
+#ifdef __Fuchsia__
+static char **
+do_setup_env(struct ssh *ssh, Session *s, const char *shell);
+#endif
+
 /*
  * This is called to fork and execute a command when we have no tty.  This
  * will call do_child from the child, and server_loop from the parent after
@@ -442,7 +453,8 @@
 	session_proctitle(s);
 
 #ifdef __Fuchsia__
-	pid = fuchsia_launch_child(command, pin[0], pout[1], perr[1], false);
+	char** env = do_setup_env(ssh, s, "");
+	pid = fuchsia_launch_child(command, env, pin[0], pout[1], perr[1], false);
 	if (pid <= 0) {
 #ifdef USE_PIPES
 		close(pin[0]);
@@ -616,7 +628,8 @@
 	}
 
 #ifdef __Fuchsia__
-	pid = fuchsia_launch_child(command, ttyfd, ttyfd, ttyfd, true);
+	char** env = do_setup_env(ssh, s, "");
+	pid = fuchsia_launch_child(command, env, ttyfd, ttyfd, ttyfd, true);
 
 #else
 	/* Fork the child. */