*/
#include "includes.h"
-RCSID("$OpenBSD: session.c,v 1.113 2001/12/19 15:43:11 stevesk Exp $");
+RCSID("$OpenBSD: session.c,v 1.129 2002/03/18 03:41:08 provos Exp $");
#include "ssh.h"
#include "ssh1.h"
#include "canohost.h"
#include "session.h"
-#ifdef WITH_IRIX_PROJECT
-#include <proj.h>
-#endif /* WITH_IRIX_PROJECT */
-#ifdef WITH_IRIX_JOBS
-#include <sys/resource.h>
-#endif
-#ifdef WITH_IRIX_AUDIT
-#include <sat.h>
-#endif /* WITH_IRIX_AUDIT */
-
-#if defined(HAVE_USERSEC_H)
-#include <usersec.h>
-#endif
-
#ifdef HAVE_CYGWIN
#include <windows.h>
#include <sys/cygwin.h>
#define is_winnt (GetVersion() < 0x80000000)
#endif
-/* AIX limits */
-#if defined(HAVE_GETUSERATTR) && !defined(S_UFSIZE_HARD) && defined(S_UFSIZE)
-# define S_UFSIZE_HARD S_UFSIZE "_hard"
-# define S_UCPU_HARD S_UCPU "_hard"
-# define S_UDATA_HARD S_UDATA "_hard"
-# define S_USTACK_HARD S_USTACK "_hard"
-# define S_URSS_HARD S_URSS "_hard"
-# define S_UCORE_HARD S_UCORE "_hard"
-# define S_UNOFILE_HARD S_UNOFILE "_hard"
-#endif
-
-#ifdef _AIX
-# include <uinfo.h>
-#endif
-
/* types */
#define TTYSZ 64
int display_number;
char *display;
int screen;
- char *auth_display[2];
+ char *auth_display;
char *auth_proto;
char *auth_data;
int single_connection;
#endif /* WITH_AIXAUTHENTICATE */
#ifdef HAVE_LOGIN_CAP
-static login_cap_t *lc;
+login_cap_t *lc;
#endif
void
close(startup_pipe);
startup_pipe = -1;
}
-#if defined(HAVE_LOGIN_CAP) && defined(HAVE_PW_CLASS_IN_PASSWD)
- if ((lc = login_getclass(authctxt->pw->pw_class)) == NULL) {
- error("unable to get login class");
- return;
- }
-#ifdef BSD_AUTH
- if (auth_approval(NULL, lc, authctxt->pw->pw_name, "ssh") <= 0) {
- packet_disconnect("Approval failure for %s",
- authctxt->pw->pw_name);
- }
-#endif
-#endif
#ifdef WITH_AIXAUTHENTICATE
/* We don't have a pty yet, so just label the line as "ssh" */
if (loginsuccess(authctxt->user,
- get_canonical_hostname(options.reverse_mapping_check),
+ get_canonical_hostname(options.verify_reverse_mapping),
"ssh", &aixloginmsg) < 0)
aixloginmsg = NULL;
#endif /* WITH_AIXAUTHENTICATE */
{
Session *s;
char *command;
- int success, type, plen, screen_flag;
+ int success, type, screen_flag;
int compression_level = 0, enable_compression_after_reply = 0;
u_int proto_len, data_len, dlen;
success = 0;
/* Get a packet from the client. */
- type = packet_read(&plen);
+ type = packet_read();
/* Process the packet. */
switch (type) {
case SSH_CMSG_REQUEST_COMPRESSION:
- packet_integrity_check(plen, 4, type);
compression_level = packet_get_int();
+ packet_check_eom();
if (compression_level < 1 || compression_level > 9) {
packet_send_debug("Received illegal compression level %d.",
compression_level);
} else {
s->screen = 0;
}
- packet_done();
+ packet_check_eom();
success = session_setup_x11fwd(s);
if (!success) {
xfree(s->auth_proto);
verbose("Kerberos TGT passing disabled.");
} else {
char *kdata = packet_get_string(&dlen);
- packet_integrity_check(plen, 4 + dlen, type);
+ packet_check_eom();
/* XXX - 0x41, see creds_to_radix version */
if (kdata[0] != 0x41) {
} else {
/* Accept AFS token. */
char *token = packet_get_string(&dlen);
- packet_integrity_check(plen, 4 + dlen, type);
+ packet_check_eom();
if (auth_afs_token(s->authctxt, token))
success = 1;
} else {
do_exec(s, NULL);
}
- packet_done();
+ packet_check_eom();
session_close(s);
return;
}
record_utmp_only(pid, s->tty, s->pw->pw_name,
- get_remote_name_or_ip(utmp_len, options.reverse_mapping_check),
+ get_remote_name_or_ip(utmp_len, options.verify_reverse_mapping),
(struct sockaddr *)&from);
}
#endif
original_command = NULL;
}
+
/* administrative, login(1)-like work */
void
do_login(Session *s, const char *command)
if (packet_connection_is_on_socket()) {
fromlen = sizeof(from);
if (getpeername(packet_get_connection_in(),
- (struct sockaddr *) & from, &fromlen) < 0) {
+ (struct sockaddr *) & from, &fromlen) < 0) {
debug("getpeername: %.100s", strerror(errno));
fatal_cleanup();
}
/* Record that there was a login on that tty from the remote host. */
record_login(pid, s->tty, pw->pw_name, pw->pw_uid,
- get_remote_name_or_ip(utmp_len, options.reverse_mapping_check),
+ get_remote_name_or_ip(utmp_len, options.verify_reverse_mapping),
(struct sockaddr *)&from);
#ifdef USE_PAM
fclose(f);
}
-#ifdef USE_PAM
-/*
- * Sets any environment variables which have been specified by PAM
- */
-void do_pam_environment(char ***env, u_int *envsize)
+void copy_environment(char **source, char ***env, u_int *envsize)
{
- char *equals, var_name[512], var_val[512];
- char **pam_env;
+ char *var_name, *var_val;
int i;
- if ((pam_env = fetch_pam_environment()) == NULL)
+ if (source == NULL)
return;
- for(i = 0; pam_env[i] != NULL; i++) {
- if ((equals = strstr(pam_env[i], "=")) == NULL)
+ for(i = 0; source[i] != NULL; i++) {
+ var_name = xstrdup(source[i]);
+ if ((var_val = strstr(var_name, "=")) == NULL) {
+ xfree(var_name);
continue;
-
- if (strlen(pam_env[i]) < (sizeof(var_name) - 1)) {
- memset(var_name, '\0', sizeof(var_name));
- memset(var_val, '\0', sizeof(var_val));
-
- strncpy(var_name, pam_env[i], equals - pam_env[i]);
- strcpy(var_val, equals + 1);
-
- debug3("PAM environment: %s=%s", var_name, var_val);
-
- child_set_env(env, envsize, var_name, var_val);
}
- }
-}
-#endif /* USE_PAM */
-
-#ifdef HAVE_CYGWIN
-void copy_environment(char ***env, u_int *envsize)
-{
- char *equals, var_name[512], var_val[512];
- int i;
-
- for(i = 0; environ[i] != NULL; i++) {
- if ((equals = strstr(environ[i], "=")) == NULL)
- continue;
-
- if (strlen(environ[i]) < (sizeof(var_name) - 1)) {
- memset(var_name, '\0', sizeof(var_name));
- memset(var_val, '\0', sizeof(var_val));
-
- strncpy(var_name, environ[i], equals - environ[i]);
- strcpy(var_val, equals + 1);
-
- debug3("Copy environment: %s=%s", var_name, var_val);
+ *var_val++ = '\0';
- child_set_env(env, envsize, var_name, var_val);
- }
- }
-}
-#endif
-
-#if defined(HAVE_GETUSERATTR)
-/*
- * AIX-specific login initialisation
- */
-void set_limit(char *user, char *soft, char *hard, int resource, int mult)
-{
- struct rlimit rlim;
- int slim, hlim;
-
- getrlimit(resource, &rlim);
-
- slim = 0;
- if (getuserattr(user, soft, &slim, SEC_INT) != -1) {
- if (slim < 0) {
- rlim.rlim_cur = RLIM_INFINITY;
- } else if (slim != 0) {
- /* See the wackiness below */
- if (rlim.rlim_cur == slim * mult)
- slim = 0;
- else
- rlim.rlim_cur = slim * mult;
- }
- }
-
- hlim = 0;
- if (getuserattr(user, hard, &hlim, SEC_INT) != -1) {
- if (hlim < 0) {
- rlim.rlim_max = RLIM_INFINITY;
- } else if (hlim != 0) {
- rlim.rlim_max = hlim * mult;
- }
- }
-
- /*
- * XXX For cpu and fsize the soft limit is set to the hard limit
- * if the hard limit is left at its default value and the soft limit
- * is changed from its default value, either by requesting it
- * (slim == 0) or by setting it to the current default. At least
- * that's how rlogind does it. If you're confused you're not alone.
- * Bug or feature? AIX 4.3.1.2
- */
- if ((!strcmp(soft, "fsize") || !strcmp(soft, "cpu"))
- && hlim == 0 && slim != 0)
- rlim.rlim_max = rlim.rlim_cur;
- /* A specified hard limit limits the soft limit */
- else if (hlim > 0 && rlim.rlim_cur > rlim.rlim_max)
- rlim.rlim_cur = rlim.rlim_max;
- /* A soft limit can increase a hard limit */
- else if (rlim.rlim_cur > rlim.rlim_max)
- rlim.rlim_max = rlim.rlim_cur;
-
- if (setrlimit(resource, &rlim) != 0)
- error("setrlimit(%.10s) failed: %.100s", soft, strerror(errno));
-}
-
-void set_limits_from_userattr(char *user)
-{
- int mask;
- char buf[16];
-
- set_limit(user, S_UFSIZE, S_UFSIZE_HARD, RLIMIT_FSIZE, 512);
- set_limit(user, S_UCPU, S_UCPU_HARD, RLIMIT_CPU, 1);
- set_limit(user, S_UDATA, S_UDATA_HARD, RLIMIT_DATA, 512);
- set_limit(user, S_USTACK, S_USTACK_HARD, RLIMIT_STACK, 512);
- set_limit(user, S_URSS, S_URSS_HARD, RLIMIT_RSS, 512);
- set_limit(user, S_UCORE, S_UCORE_HARD, RLIMIT_CORE, 512);
-#if defined(S_UNOFILE)
- set_limit(user, S_UNOFILE, S_UNOFILE_HARD, RLIMIT_NOFILE, 1);
-#endif
-
- if (getuserattr(user, S_UMASK, &mask, SEC_INT) != -1) {
- /* Convert decimal to octal */
- (void) snprintf(buf, sizeof(buf), "%d", mask);
- if (sscanf(buf, "%o", &mask) == 1)
- umask(mask);
+ debug3("Copy environment: %s=%s", var_name, var_val);
+ child_set_env(env, envsize, var_name, var_val);
+
+ xfree(var_name);
}
}
-#endif /* defined(HAVE_GETUSERATTR) */
-/*
- * 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)
+static char **
+do_setup_env(Session *s, const char *shell)
{
- const char *shell, *hostname = NULL, *cp = NULL;
- struct passwd *pw = s->pw;
char buf[256];
- char cmd[1024];
- FILE *f = NULL;
- u_int envsize, i;
+ u_int i, envsize;
char **env;
- extern char **environ;
- struct stat st;
- char *argv[10];
- int do_xauth;
-#ifdef WITH_IRIX_PROJECT
- prid_t projid;
-#endif /* WITH_IRIX_PROJECT */
-#ifdef WITH_IRIX_JOBS
- jid_t jid = 0;
-#else
-#ifdef WITH_IRIX_ARRAY
- int jid = 0;
-#endif /* WITH_IRIX_ARRAY */
-#endif /* WITH_IRIX_JOBS */
-
- do_xauth =
- s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL;
-
- /* 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;
-
-#if !defined(HAVE_OSF_SIA)
- if (!options.use_login) {
-# 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 /* HAVE_LOGIN_CAP */
- if (pw->pw_uid)
- f = fopen(_PATH_NOLOGIN, "r");
-# endif /* HAVE_LOGIN_CAP */
- if (f) {
- /* /etc/nologin exists. Print its contents and exit. */
- while (fgets(buf, sizeof(buf), f))
- fputs(buf, stderr);
- fclose(f);
- exit(254);
- }
- }
-#endif /* HAVE_OSF_SIA */
-
- /* Set login name, uid, gid, and groups. */
- /* 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 */
-#ifdef HAVE_CYGWIN
- if (is_winnt) {
-#else
- if (getuid() == 0 || geteuid() == 0) {
-#endif
-# ifdef HAVE_GETUSERATTR
- set_limits_from_userattr(pw->pw_name);
-# endif /* HAVE_GETUSERATTR */
-# ifdef HAVE_LOGIN_CAP
- if (setusercontext(lc, pw, pw->pw_uid,
- (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) {
- perror("unable to set user context");
- exit(1);
- }
-# else /* HAVE_LOGIN_CAP */
-#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 */
-# ifdef WITH_IRIX_JOBS
- jid = jlimit_startjob(pw->pw_name, pw->pw_uid, "interactive");
- if (jid == -1) {
- fatal("Failed to create job container: %.100s",
- strerror(errno));
- }
-# endif /* WITH_IRIX_JOBS */
-# ifdef WITH_IRIX_ARRAY
- /* initialize array session */
- if (jid == 0) {
- if (newarraysess() != 0)
- fatal("Failed to set up new array session: %.100s",
- strerror(errno));
- }
-# endif /* WITH_IRIX_ARRAY */
-# ifdef WITH_IRIX_PROJECT
- /* initialize irix project info */
- if ((projid = getdfltprojuser(pw->pw_name)) == -1) {
- debug("Failed to get project id, using projid 0");
- projid = 0;
- }
- if (setprid(projid))
- fatal("Failed to initialize project %d for %s: %.100s",
- (int)projid, pw->pw_name, strerror(errno));
-# endif /* WITH_IRIX_PROJECT */
-#ifdef WITH_IRIX_AUDIT
- if (sysconf(_SC_AUDIT)) {
- debug("Setting sat id to %d", (int) pw->pw_uid);
- if (satsetid(pw->pw_uid))
- debug("error setting satid: %.100s", strerror(errno));
- }
-#endif /* WITH_IRIX_AUDIT */
-
-#ifdef _AIX
- /*
- * AIX has a "usrinfo" area where logname and
- * other stuff is stored - a few applications
- * actually use this and die if it's not set
- */
- if (s->ttyfd == -1)
- s->tty[0] = '\0';
- cp = xmalloc(22 + strlen(s->tty) +
- 2 * strlen(pw->pw_name));
- i = sprintf(cp, "LOGNAME=%s%cNAME=%s%cTTY=%s%c%c",
- pw->pw_name, 0, pw->pw_name, 0, s->tty, 0, 0);
- if (usrinfo(SETUINFO, cp, i) == -1)
- fatal("Couldn't set usrinfo: %s",
- strerror(errno));
- debug3("AIX/UsrInfo: set len %d", i);
- xfree(cp);
-#endif
-
- /* Permanently switch to the desired uid. */
- permanently_set_uid(pw);
-# endif /* HAVE_LOGIN_CAP */
- }
-#endif /* HAVE_OSF_SIA */
-
-#ifdef HAVE_CYGWIN
- if (is_winnt)
-#endif
- if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
- fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
- }
- /*
- * 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
+ struct passwd *pw = s->pw;
/* Initialize the environment. */
envsize = 100;
* The Windows environment contains some setting which are
* important for a running system. They must not be dropped.
*/
- copy_environment(&env, &envsize);
+ copy_environment(environ, &env, &envsize);
#endif
if (!options.use_login) {
while (custom_environment) {
struct envstring *ce = custom_environment;
char *s = ce->s;
- int i;
+
for (i = 0; s[i] != '=' && s[i]; i++)
;
if (s[i] == '=') {
}
snprintf(buf, sizeof buf, "%.50s %d %d",
- get_remote_ipaddr(), get_remote_port(), get_local_port());
+ get_remote_ipaddr(), get_remote_port(), get_local_port());
child_set_env(&env, &envsize, "SSH_CLIENT", buf);
if (s->ttyfd != -1)
original_command);
#ifdef _AIX
- if ((cp = getenv("AUTHSTATE")) != NULL)
- child_set_env(&env, &envsize, "AUTHSTATE", cp);
- if ((cp = getenv("KRB5CCNAME")) != NULL)
- child_set_env(&env, &envsize, "KRB5CCNAME", cp);
- read_environment_file(&env, &envsize, "/etc/environment");
+ {
+ char *cp;
+
+ if ((cp = getenv("AUTHSTATE")) != NULL)
+ child_set_env(&env, &envsize, "AUTHSTATE", cp);
+ if ((cp = getenv("KRB5CCNAME")) != NULL)
+ child_set_env(&env, &envsize, "KRB5CCNAME", cp);
+ read_environment_file(&env, &envsize, "/etc/environment");
+ }
#endif
#ifdef KRB4
if (s->authctxt->krb4_ticket_file)
#endif
#ifdef USE_PAM
/* Pull in any environment variables that may have been set by PAM. */
- do_pam_environment(&env, &envsize);
+ copy_environment(fetch_pam_environment(), &env, &envsize);
#endif /* USE_PAM */
if (auth_get_socket_name() != NULL)
for (i = 0; env[i]; i++)
fprintf(stderr, " %.200s\n", env[i]);
}
+ 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 %.100s 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. */
+static void
+do_setusercontext(struct passwd *pw)
+{
+#ifdef HAVE_CYGWIN
+ if (is_winnt) {
+#else /* HAVE_CYGWIN */
+ if (getuid() == 0 || geteuid() == 0) {
+#endif /* HAVE_CYGWIN */
+#ifdef HAVE_GETUSERATTR
+ set_limits_from_userattr(pw->pw_name);
+#endif /* HAVE_GETUSERATTR */
+#ifdef HAVE_LOGIN_CAP
+ 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) */
+ /* 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);
+}
+
+/*
+ * 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);
+# ifdef _AIX
+ aix_usrinfo(pw, s->tty, s->ttyfd);
+# endif /* _AIX */
+ 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);
+
/* we have to stash the hostname before we close our socket. */
if (options.use_login)
hostname = get_remote_name_or_ip(utmp_len,
- options.reverse_mapping_check);
+ options.verify_reverse_mapping);
/*
* Close the connection descriptors; note that this is the child, and
* the server will still have the socket open, and it is important
close(i);
/*
- * Must take new environment into use so that .ssh/rc, /etc/sshrc and
- * xauth are run in the proper environment.
+ * Must take new environment into use so that .ssh/rc,
+ * /etc/ssh/sshrc and xauth are run in the proper environment.
*/
environ = env;
#endif
}
- /*
- * Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first
- * in this order).
- */
- if (!options.use_login) {
- /* 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 %.100s add "
- "%.100s %.100s %.100s\n",
- options.xauth_location, s->auth_display[0],
- s->auth_proto, s->auth_data);
- if (s->auth_display[1])
- fprintf(stderr,
- "add %.100s %.100s %.100s\n",
- s->auth_display[1],
- 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[0], s->auth_proto,
- s->auth_data);
- if (s->auth_display[1])
- fprintf(f, "add %s %s %s\n",
- s->auth_display[1], s->auth_proto,
- s->auth_data);
- pclose(f);
- } else {
- fprintf(stderr, "Could not run %s\n",
- cmd);
- }
- }
- /* Get the last component of the shell name. */
- cp = strrchr(shell, '/');
- if (cp)
- cp++;
- else
- cp = shell;
- }
+ if (!options.use_login)
+ do_rc_files(s, shell);
/* restore SIGPIPE for child */
signal(SIGPIPE, SIG_DFL);
+ if (options.use_login) {
+ /* Launch login(1). */
+
+ execl(LOGIN_PROGRAM, "login", "-h", hostname,
+#ifdef LOGIN_NEEDS_TERM
+ (s->term ? s->term : "unknown"),
+#endif /* LOGIN_NEEDS_TERM */
+ "-p", "-f", "--", pw->pw_name, (char *)NULL);
+
+ /* Login couldn't be executed, die. */
+
+ perror("login");
+ exit(1);
+ }
+
+ /* Get the last component of the shell name. */
+ if ((shell0 = strrchr(shell, '/')) != NULL)
+ shell0++;
+ else
+ shell0 = shell;
+
/*
* If we have no command, execute the shell. In this case, the shell
* name to be passed in argv[0] is preceded by '-' to indicate that
* this is a login shell.
*/
if (!command) {
- if (!options.use_login) {
- char buf[256];
-
- /* Start the shell. Set initial character to '-'. */
- buf[0] = '-';
- strlcpy(buf + 1, cp, sizeof(buf) - 1);
+ char argv0[256];
- /* Execute the shell. */
- argv[0] = buf;
- argv[1] = NULL;
- execve(shell, argv, env);
+ /* Start the shell. Set initial character to '-'. */
+ argv0[0] = '-';
- /* Executing the shell failed. */
+ if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1)
+ >= sizeof(argv0) - 1) {
+ errno = EINVAL;
perror(shell);
exit(1);
+ }
- } else {
- /* Launch login(1). */
-
- execl(LOGIN_PROGRAM, "login", "-h", hostname,
-#ifdef LOGIN_NEEDS_TERM
- s->term? s->term : "unknown",
-#endif
- "-p", "-f", "--", pw->pw_name, (char *)NULL);
-
- /* Login couldn't be executed, die. */
+ /* Execute the shell. */
+ argv[0] = argv0;
+ argv[1] = NULL;
+ execve(shell, argv, env);
- perror("login");
- exit(1);
- }
+ /* Executing the shell failed. */
+ perror(shell);
+ exit(1);
}
/*
* Execute the command using the user's shell. This uses the -c
* option to execute the command.
*/
- argv[0] = (char *) cp;
+ argv[0] = (char *) shell0;
argv[1] = "-c";
argv[2] = (char *) command;
argv[3] = NULL;
s->row = packet_get_int();
s->xpixel = packet_get_int();
s->ypixel = packet_get_int();
- packet_done();
+ packet_check_eom();
pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
return 1;
}
/* Set window size from the packet. */
pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
- packet_done();
+ packet_check_eom();
session_proctitle(s);
return 1;
}
char *cmd, *subsys = packet_get_string(&len);
int i;
- packet_done();
- log("subsystem request for %s", subsys);
+ packet_check_eom();
+ log("subsystem request for %.100s", subsys);
for (i = 0; i < options.num_subsystems; i++) {
if (strcmp(subsys, options.subsystem_name[i]) == 0) {
s->is_subsystem = 1;
do_exec(s, cmd);
success = 1;
+ break;
}
}
if (!success)
- log("subsystem request for %s failed, subsystem not found",
+ log("subsystem request for %.100s failed, subsystem not found",
subsys);
xfree(subsys);
s->auth_proto = packet_get_string(NULL);
s->auth_data = packet_get_string(NULL);
s->screen = packet_get_int();
- packet_done();
+ packet_check_eom();
success = session_setup_x11fwd(s);
if (!success) {
static int
session_shell_req(Session *s)
{
- packet_done();
+ packet_check_eom();
do_exec(s, NULL);
return 1;
}
{
u_int len;
char *command = packet_get_string(&len);
- packet_done();
+ packet_check_eom();
do_exec(s, command);
xfree(command);
return 1;
session_auth_agent_req(Session *s)
{
static int called = 0;
- packet_done();
+ packet_check_eom();
if (no_agent_forwarding_flag) {
debug("session_auth_agent_req: no_agent_forwarding_flag");
return 0;
}
}
-void
-session_input_channel_req(int id, void *arg)
+int
+session_input_channel_req(Channel *c, const char *rtype)
{
- u_int len;
- int reply;
int success = 0;
- char *rtype;
Session *s;
- Channel *c;
-
- rtype = packet_get_string(&len);
- reply = packet_get_char();
- s = session_by_channel(id);
- if (s == NULL)
- fatal("session_input_channel_req: channel %d: no session", id);
- c = channel_lookup(id);
- if (c == NULL)
- fatal("session_input_channel_req: channel %d: bad channel", id);
-
- debug("session_input_channel_req: session %d channel %d request %s reply %d",
- s->self, id, rtype, reply);
+ if ((s = session_by_channel(c->self)) == NULL) {
+ log("session_input_channel_req: no session %d req %.100s",
+ c->self, rtype);
+ return 0;
+ }
+ debug("session_input_channel_req: session %d req %s", s->self, rtype);
/*
* a session is in LARVAL state until a shell, a command
if (strcmp(rtype, "window-change") == 0) {
success = session_window_change_req(s);
}
-
- if (reply) {
- packet_start(success ?
- SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
- packet_put_int(c->remote_id);
- packet_send();
- }
- xfree(rtype);
+ return success;
}
void
channel_set_fds(s->chanid,
fdout, fdin, fderr,
fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
- 1);
+ 1,
+ CHAN_SES_WINDOW_DEFAULT);
}
/*
/* Record that the user has logged out. */
if (s->pid != 0)
- record_logout(s->pid, s->tty);
+ record_logout(s->pid, s->tty, s->pw->pw_name);
/* Release the pseudo-tty. */
pty_release(s->tty);
session_exit_message(Session *s, int status)
{
Channel *c;
- if (s == NULL)
- fatal("session_close: no session");
- c = channel_lookup(s->chanid);
- if (c == NULL)
+
+ if ((c = channel_lookup(s->chanid)) == NULL)
fatal("session_exit_message: session %d: no channel %d",
s->self, s->chanid);
debug("session_exit_message: session %d channel %d pid %d",
s->self, s->chanid, s->pid);
if (WIFEXITED(status)) {
- channel_request_start(s->chanid,
- "exit-status", 0);
+ channel_request_start(s->chanid, "exit-status", 0);
packet_put_int(WEXITSTATUS(status));
packet_send();
} else if (WIFSIGNALED(status)) {
- channel_request_start(s->chanid,
- "exit-signal", 0);
+ channel_request_start(s->chanid, "exit-signal", 0);
packet_put_int(WTERMSIG(status));
#ifdef WCOREDUMP
packet_put_char(WCOREDUMP(status));
xfree(s->term);
if (s->display)
xfree(s->display);
- if (s->auth_display[0])
- xfree(s->auth_display[0]);
- if (s->auth_display[1])
- xfree(s->auth_display[1]);
+ if (s->auth_display)
+ xfree(s->auth_display);
if (s->auth_data)
xfree(s->auth_data);
if (s->auth_proto)
return 0;
}
s->display_number = x11_create_display_inet(options.x11_display_offset,
- options.gateway_ports);
+ options.x11_use_localhost, s->single_connection);
if (s->display_number == -1) {
debug("x11_create_display_inet failed.");
return 0;
* authorization entry is added with xauth(1). This will be
* different than the DISPLAY string for localhost displays.
*/
- s->auth_display[1] = NULL;
- if (!options.gateway_ports) {
- struct utsname uts;
-
+ if (options.x11_use_localhost) {
snprintf(display, sizeof display, "localhost:%d.%d",
s->display_number, s->screen);
- snprintf(auth_display, sizeof auth_display, "%.400s/unix:%d.%d",
- hostname, s->display_number, s->screen);
+ snprintf(auth_display, sizeof auth_display, "unix:%d.%d",
+ s->display_number, s->screen);
s->display = xstrdup(display);
- s->auth_display[0] = xstrdup(auth_display);
- /*
- * Xlib may use gethostbyname() or uname() hostname to
- * look up authorization data for FamilyLocal; see:
- * xc/lib/xtrans/Xtrans.c:TRANS(GetHostname)
- * We just add authorization entries with both
- * hostname and nodename if they are different.
- */
- if (uname(&uts) == -1)
- fatal("uname: %.100s", strerror(errno));
- if (strcmp(hostname, uts.nodename) != 0) {
- snprintf(auth_display, sizeof auth_display,
- "%.400s/unix:%d.%d", uts.nodename,
- s->display_number, s->screen);
- s->auth_display[1] = xstrdup(auth_display);
- }
+ s->auth_display = xstrdup(auth_display);
} else {
#ifdef IPADDR_IN_DISPLAY
struct hostent *he;
s->display_number, s->screen);
#endif
s->display = xstrdup(display);
- s->auth_display[0] = xstrdup(display);
+ s->auth_display = xstrdup(display);
}
return 1;