+ return env;
+}
+
+/*
+ * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found
+ * first in this order).
+ */
+static void
+do_rc_files(Session *s, const char *shell)
+{
+ FILE *f = NULL;
+ char cmd[1024];
+ int do_xauth;
+ struct stat st;
+
+ do_xauth =
+ s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL;
+
+ /* ignore _PATH_SSH_USER_RC for subsystems */
+ if (!s->is_subsystem && (stat(_PATH_SSH_USER_RC, &st) >= 0)) {
+ snprintf(cmd, sizeof cmd, "%s -c '%s %s'",
+ shell, _PATH_BSHELL, _PATH_SSH_USER_RC);
+ if (debug_flag)
+ fprintf(stderr, "Running %s\n", cmd);
+ f = popen(cmd, "w");
+ if (f) {
+ if (do_xauth)
+ fprintf(f, "%s %s\n", s->auth_proto,
+ s->auth_data);
+ pclose(f);
+ } else
+ fprintf(stderr, "Could not run %s\n",
+ _PATH_SSH_USER_RC);
+ } else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) {
+ if (debug_flag)
+ fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,
+ _PATH_SSH_SYSTEM_RC);
+ f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w");
+ if (f) {
+ if (do_xauth)
+ fprintf(f, "%s %s\n", s->auth_proto,
+ s->auth_data);
+ pclose(f);
+ } else
+ fprintf(stderr, "Could not run %s\n",
+ _PATH_SSH_SYSTEM_RC);
+ } else if (do_xauth && options.xauth_location != NULL) {
+ /* Add authority data to .Xauthority if appropriate. */
+ if (debug_flag) {
+ fprintf(stderr,
+ "Running %.500s add "
+ "%.100s %.100s %.100s\n",
+ options.xauth_location, s->auth_display,
+ s->auth_proto, s->auth_data);
+ }
+ snprintf(cmd, sizeof cmd, "%s -q -",
+ options.xauth_location);
+ f = popen(cmd, "w");
+ if (f) {
+ fprintf(f, "add %s %s %s\n",
+ s->auth_display, s->auth_proto,
+ s->auth_data);
+ pclose(f);
+ } else {
+ fprintf(stderr, "Could not run %s\n",
+ cmd);
+ }
+ }
+}
+
+static void
+do_nologin(struct passwd *pw)
+{
+ FILE *f = NULL;
+ char buf[1024];
+
+#ifdef HAVE_LOGIN_CAP
+ if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid)
+ f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN,
+ _PATH_NOLOGIN), "r");
+#else
+ if (pw->pw_uid)
+ f = fopen(_PATH_NOLOGIN, "r");
+#endif
+ if (f) {
+ /* /etc/nologin exists. Print its contents and exit. */
+ while (fgets(buf, sizeof(buf), f))
+ fputs(buf, stderr);
+ fclose(f);
+ exit(254);
+ }
+}
+
+/* Set login name, uid, gid, and groups. */
+void
+do_setusercontext(struct passwd *pw)
+{
+ char tty='\0';
+
+#ifdef HAVE_CYGWIN
+ if (is_winnt) {
+#else /* HAVE_CYGWIN */
+ if (getuid() == 0 || geteuid() == 0) {
+#endif /* HAVE_CYGWIN */
+#ifdef HAVE_SETPCRED
+ setpcred(pw->pw_name);
+#endif /* HAVE_SETPCRED */
+#ifdef HAVE_LOGIN_CAP
+#ifdef __bsdi__
+ setpgid(0, 0);
+#endif
+ if (setusercontext(lc, pw, pw->pw_uid,
+ (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) {
+ perror("unable to set user context");
+ exit(1);
+ }
+#else
+# if defined(HAVE_GETLUID) && defined(HAVE_SETLUID)
+ /* Sets login uid for accounting */
+ if (getluid() == -1 && setluid(pw->pw_uid) == -1)
+ error("setluid: %s", strerror(errno));
+# endif /* defined(HAVE_GETLUID) && defined(HAVE_SETLUID) */
+
+ if (setlogin(pw->pw_name) < 0)
+ error("setlogin failed: %s", strerror(errno));
+ if (setgid(pw->pw_gid) < 0) {
+ perror("setgid");
+ exit(1);
+ }
+ /* Initialize the group list. */
+ if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
+ perror("initgroups");
+ exit(1);
+ }
+ endgrent();
+# ifdef USE_PAM
+ /*
+ * PAM credentials may take the form of supplementary groups.
+ * These will have been wiped by the above initgroups() call.
+ * Reestablish them here.
+ */
+ do_pam_setcred(0);
+# endif /* USE_PAM */
+# if defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY)
+ irix_setusercontext(pw);
+# endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */
+# ifdef _AIX
+ /* XXX: Disable tty setting. Enabled if required later */
+ aix_usrinfo(pw, &tty, -1);
+# endif /* _AIX */
+ /* Permanently switch to the desired uid. */
+ permanently_set_uid(pw);
+#endif
+ }
+ if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
+ fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
+}
+
+static void
+launch_login(struct passwd *pw, const char *hostname)
+{
+ /* Launch login(1). */
+
+ execl(LOGIN_PROGRAM, "login", "-h", hostname,
+#ifdef xxxLOGIN_NEEDS_TERM
+ (s->term ? s->term : "unknown"),
+#endif /* LOGIN_NEEDS_TERM */
+#ifdef LOGIN_NO_ENDOPT
+ "-p", "-f", pw->pw_name, (char *)NULL);
+#else
+ "-p", "-f", "--", pw->pw_name, (char *)NULL);
+#endif
+
+ /* Login couldn't be executed, die. */
+
+ perror("login");
+ exit(1);
+}
+
+/*
+ * Performs common processing for the child, such as setting up the
+ * environment, closing extra file descriptors, setting the user and group
+ * ids, and executing the command or shell.
+ */
+void
+do_child(Session *s, const char *command)
+{
+ extern char **environ;
+ char **env;
+ char *argv[10];
+ const char *shell, *shell0, *hostname = NULL;
+ struct passwd *pw = s->pw;
+ u_int i;
+
+ /* remove hostkey from the child's memory */
+ destroy_sensitive_data();
+
+ /* login(1) is only called if we execute the login shell */
+ if (options.use_login && command != NULL)
+ options.use_login = 0;
+
+ /*
+ * Login(1) does this as well, and it needs uid 0 for the "-h"
+ * switch, so we let login(1) to this for us.
+ */
+ if (!options.use_login) {
+#ifdef HAVE_OSF_SIA
+ session_setup_sia(pw->pw_name, s->ttyfd == -1 ? NULL : s->tty);
+ if (!check_quietlogin(s, command))
+ do_motd();
+#else /* HAVE_OSF_SIA */
+ do_nologin(pw);
+ do_setusercontext(pw);
+#endif /* HAVE_OSF_SIA */
+ }
+
+ /*
+ * Get the shell from the password data. An empty shell field is
+ * legal, and means /bin/sh.
+ */
+ shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
+#ifdef HAVE_LOGIN_CAP
+ shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);
+#endif
+
+ env = do_setup_env(s, shell);
+