+/* $OpenBSD: session.c,v 1.209 2006/07/11 20:07:25 stevesk Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*/
#include "includes.h"
-RCSID("$OpenBSD: session.c,v 1.181 2004/12/23 17:35:48 markus Exp $");
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+
+#include <errno.h>
+#include <grp.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#include <pwd.h>
+#include <signal.h>
+#include <arpa/inet.h>
#include "ssh.h"
#include "ssh1.h"
#include "serverloop.h"
#include "canohost.h"
#include "session.h"
+#include "kex.h"
#include "monitor_wrap.h"
#if defined(KRB5) && defined(USE_AFS)
sunaddr.sun_family = AF_UNIX;
strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path));
- if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0)
+ if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
packet_disconnect("bind: %.100s", strerror(errno));
/* Restore the privileged uid. */
static void
display_loginmsg(void)
{
- if (buffer_len(&loginmsg) > 0) {
- buffer_append(&loginmsg, "\0", 1);
- printf("%s", (char *)buffer_ptr(&loginmsg));
- buffer_clear(&loginmsg);
- }
+ if (buffer_len(&loginmsg) > 0) {
+ buffer_append(&loginmsg, "\0", 1);
+ printf("%s", (char *)buffer_ptr(&loginmsg));
+ buffer_clear(&loginmsg);
+ }
}
void
{
setproctitle("%s", authctxt->pw->pw_name);
- /*
- * Cancel the alarm we set to limit the time taken for
- * authentication.
- */
- alarm(0);
- if (startup_pipe != -1) {
- close(startup_pipe);
- startup_pipe = -1;
- }
/* setup the channel layer */
if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
channel_permit_all_opens();
compression_level);
break;
}
- if (!options.compression) {
+ if (options.compression == COMP_NONE) {
debug2("compression disabled");
break;
}
break;
}
debug("Received TCP/IP port forwarding request.");
- channel_input_port_forward_request(s->pw->pw_uid == 0, options.gateway_ports);
+ if (channel_input_port_forward_request(s->pw->pw_uid == 0,
+ options.gateway_ports) < 0) {
+ debug("Port forwarding failed.");
+ break;
+ }
success = 1;
break;
fromlen = sizeof(from);
if (packet_connection_is_on_socket()) {
if (getpeername(packet_get_connection_in(),
- (struct sockaddr *) & from, &fromlen) < 0) {
+ (struct sockaddr *)&from, &fromlen) < 0) {
debug("getpeername: %.100s", strerror(errno));
cleanup_exit(255);
}
}
#endif
-#ifdef GSSAPI
- if (options.gss_authentication) {
- temporarily_use_uid(s->pw);
- ssh_gssapi_storecreds();
- restore_uid();
- }
-#endif
-
if (s->ttyfd != -1)
do_exec_pty(s, command);
else
if (envsize >= 1000)
fatal("child_set_env: too many env vars");
envsize += 50;
- env = (*envp) = xrealloc(env, envsize * sizeof(char *));
+ env = (*envp) = xrealloc(env, envsize, sizeof(char *));
*envsizep = envsize;
}
/* Need to set the NULL pointer at end of array beyond the new slot. */
}
#endif /* HAVE_ETC_DEFAULT_LOGIN */
-void copy_environment(char **source, char ***env, u_int *envsize)
+void
+copy_environment(char **source, char ***env, u_int *envsize)
{
char *var_name, *var_val;
int i;
/* Initialize the environment. */
envsize = 100;
- env = xmalloc(envsize * sizeof(char *));
+ env = xcalloc(envsize, sizeof(char *));
env[0] = NULL;
#ifdef HAVE_CYGWIN
# ifdef __bsdi__
setpgid(0, 0);
# endif
+#ifdef GSSAPI
+ if (options.gss_authentication) {
+ temporarily_use_uid(pw);
+ ssh_gssapi_storecreds();
+ restore_uid();
+ }
+#endif
# ifdef USE_PAM
if (options.use_pam) {
do_pam_session();
exit(1);
}
endgrent();
+#ifdef GSSAPI
+ if (options.gss_authentication) {
+ temporarily_use_uid(pw);
+ ssh_gssapi_storecreds();
+ restore_uid();
+ }
+#endif
# ifdef USE_PAM
/*
* PAM credentials may take the form of supplementary groups.
# ifdef _AIX
aix_usrinfo(pw);
# endif /* _AIX */
+#if defined(HAVE_LIBIAF) && !defined(BROKEN_LIBIAF)
+ if (set_id(pw->pw_name) != 0) {
+ exit(1);
+ }
+#endif /* HAVE_LIBIAF && !BROKEN_LIBIAF */
/* Permanently switch to the desired uid. */
permanently_set_uid(pw);
#endif
#endif
if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
+
+#ifdef WITH_SELINUX
+ ssh_selinux_setup_exec_context(pw->pw_name);
+#endif
}
static void
endpwent();
/*
- * Close any extra open file descriptors so that we don\'t have them
+ * Close any extra open file descriptors so that we don't have them
* hanging around in clients. Note that we want to do this after
* initgroups, because at least on Solaris 2.3 it leaves file
* descriptors open.
if (!check_quietlogin(s, command))
do_motd();
#else /* HAVE_OSF_SIA */
- do_nologin(pw);
+ /* When PAM is enabled we rely on it to do the nologin check */
+ if (!options.use_pam)
+ do_nologin(pw);
do_setusercontext(pw);
/*
* PAM session modules in do_setusercontext may have
}
#ifdef USE_PAM
- if (options.use_pam && !is_pam_session_open()) {
+ if (options.use_pam && !options.use_login && !is_pam_session_open()) {
+ debug3("PAM session not opened, exiting");
display_loginmsg();
exit(254);
}
*/
if (options.kerberos_get_afs_token && k_hasafs() &&
- (s->authctxt->krb5_ctx != NULL)) {
+ (s->authctxt->krb5_ctx != NULL)) {
char cell[64];
debug("Getting AFS token");
}
#endif
- /* Change current directory to the user\'s home directory. */
+ /* Change current directory to the user's home directory. */
if (chdir(pw->pw_dir) < 0) {
fprintf(stderr, "Could not chdir to home directory %s: %s\n",
pw->pw_dir, strerror(errno));
s->ttyfd = -1;
s->used = 1;
s->self = i;
+ s->x11_chanids = NULL;
debug("session_new: session %d", i);
return s;
}
return NULL;
}
+static Session *
+session_by_x11_channel(int id)
+{
+ int i, j;
+
+ for (i = 0; i < MAX_SESSIONS; i++) {
+ Session *s = &sessions[i];
+
+ if (s->x11_chanids == NULL || !s->used)
+ continue;
+ for (j = 0; s->x11_chanids[j] != -1; j++) {
+ if (s->x11_chanids[j] == id) {
+ debug("session_by_x11_channel: session %d "
+ "channel %d", s->self, id);
+ return s;
+ }
+ }
+ }
+ debug("session_by_x11_channel: unknown channel %d", id);
+ session_dump();
+ return NULL;
+}
+
static Session *
session_by_pid(pid_t pid)
{
struct stat st;
u_int len;
int success = 0;
- char *cmd, *subsys = packet_get_string(&len);
- int i;
+ char *prog, *cmd, *subsys = packet_get_string(&len);
+ u_int i;
packet_check_eom();
logit("subsystem request for %.100s", subsys);
for (i = 0; i < options.num_subsystems; i++) {
if (strcmp(subsys, options.subsystem_name[i]) == 0) {
- cmd = options.subsystem_command[i];
- if (stat(cmd, &st) < 0) {
- error("subsystem: cannot stat %s: %s", cmd,
+ prog = options.subsystem_command[i];
+ cmd = options.subsystem_args[i];
+ if (stat(prog, &st) < 0) {
+ error("subsystem: cannot stat %s: %s", prog,
strerror(errno));
break;
}
{
int success;
+ if (s->auth_proto != NULL || s->auth_data != NULL) {
+ error("session_x11_req: session %d: "
+ "x11 forwarding already active", s->self);
+ return 0;
+ }
s->single_connection = packet_get_char();
s->auth_proto = packet_get_string(NULL);
s->auth_data = packet_get_string(NULL);
for (i = 0; i < options.num_accept_env; i++) {
if (match_pattern(name, options.accept_env[i])) {
debug2("Setting env %d: %s=%s", s->num_env, name, val);
- s->env = xrealloc(s->env, sizeof(*s->env) *
- (s->num_env + 1));
+ s->env = xrealloc(s->env, s->num_env + 1,
+ sizeof(*s->env));
s->env[s->num_env].name = name;
s->env[s->num_env].val = val;
s->num_env++;
return "SIG@openssh.com";
}
+static void
+session_close_x11(int id)
+{
+ Channel *c;
+
+ if ((c = channel_by_id(id)) == NULL) {
+ debug("session_close_x11: x11 channel %d missing", id);
+ } else {
+ /* Detach X11 listener */
+ debug("session_close_x11: detach x11 channel %d", id);
+ channel_cancel_cleanup(id);
+ if (c->ostate != CHAN_OUTPUT_CLOSED)
+ chan_mark_dead(c);
+ }
+}
+
+static void
+session_close_single_x11(int id, void *arg)
+{
+ Session *s;
+ u_int i;
+
+ debug3("session_close_single_x11: channel %d", id);
+ channel_cancel_cleanup(id);
+ if ((s = session_by_x11_channel(id)) == NULL)
+ fatal("session_close_single_x11: no x11 channel %d", id);
+ for (i = 0; s->x11_chanids[i] != -1; i++) {
+ debug("session_close_single_x11: session %d: "
+ "closing channel %d", s->self, s->x11_chanids[i]);
+ /*
+ * The channel "id" is already closing, but make sure we
+ * close all of its siblings.
+ */
+ if (s->x11_chanids[i] != id)
+ session_close_x11(s->x11_chanids[i]);
+ }
+ xfree(s->x11_chanids);
+ s->x11_chanids = NULL;
+ if (s->display) {
+ xfree(s->display);
+ s->display = NULL;
+ }
+ if (s->auth_proto) {
+ xfree(s->auth_proto);
+ s->auth_proto = NULL;
+ }
+ if (s->auth_data) {
+ xfree(s->auth_data);
+ s->auth_data = NULL;
+ }
+ if (s->auth_display) {
+ xfree(s->auth_display);
+ s->auth_display = NULL;
+ }
+}
+
static void
session_exit_message(Session *s, int status)
{
/* disconnect channel */
debug("session_exit_message: release channel %d", s->chanid);
- channel_cancel_cleanup(s->chanid);
+
+ /*
+ * Adjust cleanup callback attachment to send close messages when
+ * the channel gets EOF. The session will be then be closed
+ * by session_close_by_channel when the childs close their fds.
+ */
+ channel_register_cleanup(c->self, session_close_by_channel, 1);
+
/*
* emulate a write failure with 'chan_write_failed', nobody will be
* interested in data we write.
*/
if (c->ostate != CHAN_OUTPUT_CLOSED)
chan_write_failed(c);
- s->chanid = -1;
}
void
session_close(Session *s)
{
- int i;
+ u_int i;
debug("session_close: session %d pid %ld", s->self, (long)s->pid);
if (s->ttyfd != -1)
xfree(s->term);
if (s->display)
xfree(s->display);
+ if (s->x11_chanids)
+ xfree(s->x11_chanids);
if (s->auth_display)
xfree(s->auth_display);
if (s->auth_data)
}
if (s->chanid != -1)
session_exit_message(s, status);
- session_close(s);
+ if (s->ttyfd != -1)
+ session_pty_cleanup(s);
+ s->pid = 0;
}
/*
session_close_by_channel(int id, void *arg)
{
Session *s = session_by_channel(id);
+ u_int i;
+
if (s == NULL) {
debug("session_close_by_channel: no session for id %d", id);
return;
}
/* detach by removing callback */
channel_cancel_cleanup(s->chanid);
+
+ /* Close any X11 listeners associated with this session */
+ if (s->x11_chanids != NULL) {
+ for (i = 0; s->x11_chanids[i] != -1; i++) {
+ session_close_x11(s->x11_chanids[i]);
+ s->x11_chanids[i] = -1;
+ }
+ }
+
s->chanid = -1;
session_close(s);
}
struct stat st;
char display[512], auth_display[512];
char hostname[MAXHOSTNAMELEN];
+ u_int i;
if (no_x11_forwarding_flag) {
packet_send_debug("X11 forwarding disabled in user configuration file.");
}
if (x11_create_display_inet(options.x11_display_offset,
options.x11_use_localhost, s->single_connection,
- &s->display_number) == -1) {
+ &s->display_number, &s->x11_chanids) == -1) {
debug("x11_create_display_inet failed.");
return 0;
}
+ for (i = 0; s->x11_chanids[i] != -1; i++) {
+ channel_register_cleanup(s->x11_chanids[i],
+ session_close_single_x11, 0);
+ }
/* Set up a suitable value for the DISPLAY variable. */
if (gethostname(hostname, sizeof(hostname)) < 0)
}
#endif
-#ifdef SSH_AUDIT_EVENTS
- PRIVSEP(audit_event(SSH_CONNECTION_CLOSE));
-#endif
-
/* remove agent socket */
auth_sock_cleanup_proc(authctxt->pw);