+#ifdef SESSION_HOOKS
+#define SSH_SESSION_ENV_FILE "SSH_SESSION_ENV_FILE"
+
+typedef enum { no_op, execute, clear_env, restore_env,
+ read_env, save_or_rm_env } session_action_t;
+
+static session_action_t action_order[2][5] = {
+ { clear_env, read_env, execute, save_or_rm_env, restore_env }, /*shutdown*/
+ { execute, read_env, save_or_rm_env, no_op, no_op } /*startup */
+};
+
+static
+void execute_session_hook(char* prog, Authctxt *authctxt,
+ int startup, int save)
+{
+ extern char **environ;
+
+ struct stat st;
+ char **saved_env, **tmpenv;
+ char *env_file = authctxt->session_env_file;
+ int i, status = 0;
+
+ for (i=0; i<5; i++)
+ {
+ switch (action_order[startup][i])
+ {
+ case no_op:
+ break;
+
+ case execute:
+ {
+ FILE* fp;
+ char buf[1000];
+
+ snprintf(buf,
+ sizeof(buf),
+ "%s -c '%s'",
+ authctxt->pw->pw_shell,
+ prog);
+
+ debug("executing session hook: [%s]", buf);
+ setenv(SSH_SESSION_ENV_FILE, env_file, /* overwrite = */ 1);
+
+ /* flusing is recommended in the popen(3) man page, to avoid
+ intermingling of output */
+ fflush(stdout);
+ fflush(stderr);
+ if ((fp=popen(buf, "w")) == NULL)
+ {
+ perror("Unable to run session hook");
+ return;
+ }
+ status = pclose(fp);
+ debug2("session hook executed, status=%d", status);
+ unsetenv(SSH_SESSION_ENV_FILE);
+ }
+ break;
+
+ case clear_env:
+ saved_env = environ;
+ tmpenv = (char**) malloc(sizeof(char*));
+ tmpenv[0] = NULL;
+ environ = tmpenv;
+ break;
+
+ case restore_env:
+ environ = saved_env;
+ free(tmpenv);
+ break;
+
+ case read_env:
+ if (status==0 && stat(env_file, &st)==0)
+ {
+ int envsize = 0;
+
+ debug("reading environment from %s", env_file);
+ while (environ[envsize++]) ;
+ read_environment_file(&environ, &envsize, env_file);
+ }
+ break;
+
+ case save_or_rm_env:
+ if (status==0 && save)
+ {
+ FILE* fp;
+ int envcount=0;
+
+ debug2("saving environment to %s", env_file);
+ if ((fp = fopen(env_file, "w")) == NULL) /* hmm: file perms? */
+ {
+ perror("Unable to save session hook info");
+ }
+ while (environ[envcount])
+ {
+ fprintf(fp, "%s\n", environ[envcount++]);
+ }
+ fflush(fp);
+ fclose(fp);
+ }
+ else if (stat(env_file, &st)==0)
+ {
+ debug2("removing environment file %s", env_file);
+ remove(env_file);
+ }
+ break;
+ }
+ }
+
+}
+#endif
+