X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/1d3c30dbe232d224145556c245d27d1be1e01a1e..c95add71a6006659751a44208b4ec0cedc82c0b0:/session.c diff --git a/session.c b/session.c index 13fe0187..fbdc419e 100644 --- a/session.c +++ b/session.c @@ -33,7 +33,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: session.c,v 1.67 2001/03/23 14:28:32 markus Exp $"); +RCSID("$OpenBSD: session.c,v 1.92 2001/06/19 15:40:45 markus Exp $"); #include "ssh.h" #include "ssh1.h" @@ -46,7 +46,6 @@ RCSID("$OpenBSD: session.c,v 1.67 2001/03/23 14:28:32 markus Exp $"); #include "uidswap.h" #include "compat.h" #include "channels.h" -#include "nchan.h" #include "bufaux.h" #include "auth.h" #include "auth-options.h" @@ -122,12 +121,21 @@ struct Session { Session *session_new(void); void session_set_fds(Session *s, int fdin, int fdout, int fderr); -void session_pty_cleanup(Session *s); +void session_pty_cleanup(void *session); +int session_pty_req(Session *s); void session_proctitle(Session *s); +int session_setup_x11fwd(Session *s); +void session_close(Session *s); void do_exec_pty(Session *s, const char *command); void do_exec_no_pty(Session *s, const char *command); +void do_exec(Session *s, const char *command); void do_login(Session *s, const char *command); +#ifdef LOGIN_NEEDS_UTMPX +void do_pre_login(Session *s); +#endif void do_child(Session *s, const char *command); +void do_motd(void); +int check_quietlogin(Session *s, const char *command); void do_authenticated1(Authctxt *authctxt); void do_authenticated2(Authctxt *authctxt); @@ -138,14 +146,11 @@ extern char *__progname; extern int log_stderr; extern int debug_flag; extern u_int utmp_len; - extern int startup_pipe; - -/* Local Xauthority file. */ -static char *xauthfile; +extern void destroy_sensitive_data(void); /* original command from peer. */ -char *original_command = NULL; +const char *original_command = NULL; /* data */ #define MAX_SESSIONS 10 @@ -177,6 +182,12 @@ do_authenticated(Authctxt *authctxt) 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 /* setup the channel layer */ if (!no_port_forwarding_flag && options.allow_tcp_forwarding) @@ -186,48 +197,10 @@ do_authenticated(Authctxt *authctxt) do_authenticated2(authctxt); else do_authenticated1(authctxt); -} -/* - * Remove local Xauthority file. - */ -void -xauthfile_cleanup_proc(void *ignore) -{ - debug("xauthfile_cleanup_proc called"); - - if (xauthfile != NULL) { - char *p; - unlink(xauthfile); - p = strrchr(xauthfile, '/'); - if (p != NULL) { - *p = '\0'; - rmdir(xauthfile); - } - xfree(xauthfile); - xauthfile = NULL; - } -} - -/* - * Function to perform cleanup if we get aborted abnormally (e.g., due to a - * dropped connection). - */ -void -pty_cleanup_proc(void *session) -{ - Session *s=session; - if (s == NULL) - fatal("pty_cleanup_proc: no session"); - debug("pty_cleanup_proc: %s", s->tty); - - if (s->pid != 0) { - /* Record that the user has logged out. */ - record_logout(s->pid, s->tty); - } - - /* Release the pseudo-tty. */ - pty_release(s->tty); + /* remove agent socket */ + if (auth_get_socket_name()) + auth_sock_cleanup_proc(authctxt->pw); } /* @@ -241,7 +214,7 @@ do_authenticated1(Authctxt *authctxt) { Session *s; char *command; - int success, type, fd, n_bytes, plen, screen_flag, have_pty = 0; + int success, type, plen, screen_flag; int compression_level = 0, enable_compression_after_reply = 0; u_int proto_len, data_len, dlen; @@ -274,70 +247,10 @@ do_authenticated1(Authctxt *authctxt) break; case SSH_CMSG_REQUEST_PTY: - if (no_pty_flag) { - debug("Allocating a pty not permitted for this authentication."); - break; - } - if (have_pty) - packet_disconnect("Protocol error: you already have a pty."); - - debug("Allocating pty."); - - /* Allocate a pty and open it. */ - if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, - sizeof(s->tty))) { - error("Failed to allocate pty."); - break; - } - fatal_add_cleanup(pty_cleanup_proc, (void *)s); - pty_setowner(s->pw, s->tty); - - /* Get TERM from the packet. Note that the value may be of arbitrary length. */ - s->term = packet_get_string(&dlen); - packet_integrity_check(dlen, strlen(s->term), type); - /* packet_integrity_check(plen, 4 + dlen + 4*4 + n_bytes, type); */ - /* Remaining bytes */ - n_bytes = plen - (4 + dlen + 4 * 4); - - if (strcmp(s->term, "") == 0) { - xfree(s->term); - s->term = NULL; - } - /* Get window size from the packet. */ - s->row = packet_get_int(); - s->col = packet_get_int(); - s->xpixel = packet_get_int(); - s->ypixel = packet_get_int(); - pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); - - /* Get tty modes from the packet. */ - tty_parse_modes(s->ttyfd, &n_bytes); - packet_integrity_check(plen, 4 + dlen + 4 * 4 + n_bytes, type); - - session_proctitle(s); - - /* Indicate that we now have a pty. */ - success = 1; - have_pty = 1; + success = session_pty_req(s); break; case SSH_CMSG_X11_REQUEST_FORWARDING: - if (!options.x11_forwarding) { - packet_send_debug("X11 forwarding disabled in server configuration file."); - break; - } - if (!options.xauth_location) { - packet_send_debug("No xauth program; cannot forward with spoofing."); - break; - } - if (no_x11_forwarding_flag) { - packet_send_debug("X11 forwarding not permitted for this authentication."); - break; - } - debug("Received request for X11 forwarding with auth spoofing."); - if (s->display != NULL) - packet_disconnect("Protocol error: X11 display already set."); - s->auth_proto = packet_get_string(&proto_len); s->auth_data = packet_get_string(&data_len); @@ -349,39 +262,18 @@ do_authenticated1(Authctxt *authctxt) if (!screen_flag) debug2("Buggy client: " "X11 screen flag missing"); - packet_integrity_check(plen, - 4 + proto_len + 4 + data_len + 4, type); s->screen = packet_get_int(); } else { - packet_integrity_check(plen, - 4 + proto_len + 4 + data_len, type); s->screen = 0; } - s->display = x11_create_display_inet(s->screen, options.x11_display_offset); - - if (s->display == NULL) - break; - - /* Setup to always have a local .Xauthority. */ - xauthfile = xmalloc(MAXPATHLEN); - strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN); - temporarily_use_uid(s->pw->pw_uid); - if (mkdtemp(xauthfile) == NULL) { - restore_uid(); - error("private X11 dir: mkdtemp %s failed: %s", - xauthfile, strerror(errno)); - xfree(xauthfile); - xauthfile = NULL; - /* XXXX remove listening channels */ - break; + packet_done(); + success = session_setup_x11fwd(s); + if (!success) { + xfree(s->auth_proto); + xfree(s->auth_data); + s->auth_proto = NULL; + s->auth_data = NULL; } - strlcat(xauthfile, "/cookies", MAXPATHLEN); - fd = open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600); - if (fd >= 0) - close(fd); - restore_uid(); - fatal_add_cleanup(xauthfile_cleanup_proc, NULL); - success = 1; break; case SSH_CMSG_AGENT_REQUEST_FORWARDING: @@ -417,26 +309,13 @@ do_authenticated1(Authctxt *authctxt) if (type == SSH_CMSG_EXEC_CMD) { command = packet_get_string(&dlen); debug("Exec command '%.500s'", command); - packet_integrity_check(plen, 4 + dlen, type); + do_exec(s, command); + xfree(command); } else { - command = NULL; - packet_integrity_check(plen, 0, type); + do_exec(s, NULL); } - if (forced_command != NULL) { - original_command = command; - command = forced_command; - debug("Forced command '%.500s'", forced_command); - } - if (have_pty) - do_exec_pty(s, command); - else - do_exec_no_pty(s, command); - - if (command != NULL) - xfree(command); - /* Cleanup user's local Xauthority file. */ - if (xauthfile) - xauthfile_cleanup_proc(NULL); + packet_done(); + session_close(s); return; default: @@ -488,7 +367,7 @@ do_exec_no_pty(Session *s, const char *command) session_proctitle(s); #if defined(USE_PAM) - do_pam_setcred(); + do_pam_setcred(1); #endif /* USE_PAM */ /* Fork the child. */ @@ -496,8 +375,6 @@ do_exec_no_pty(Session *s, const char *command) /* Child. Reinitialize the log since the pid has changed. */ log_init(__progname, options.log_level, options.log_facility, log_stderr); - signal(SIGPIPE, SIG_DFL); - /* * Create a new session and process group since the 4.4BSD * setlogin() affects the entire process group. @@ -605,7 +482,7 @@ do_exec_pty(Session *s, const char *command) #if defined(USE_PAM) do_pam_session(s->pw->pw_name, s->tty); - do_pam_setcred(); + do_pam_setcred(1); #endif /* Fork the child. */ @@ -613,8 +490,6 @@ do_exec_pty(Session *s, const char *command) /* Child. Reinitialize the log because the pid has changed. */ log_init(__progname, options.log_level, options.log_facility, log_stderr); - signal(SIGPIPE, SIG_DFL); - /* Close the master side of the pseudo tty. */ close(ptyfd); @@ -637,8 +512,14 @@ do_exec_pty(Session *s, const char *command) close(ttyfd); /* record login, etc. similar to login(1) */ +#ifndef HAVE_OSF_SIA if (!(options.use_login && command == NULL)) do_login(s, command); +# ifdef LOGIN_NEEDS_UTMPX + else + do_pre_login(s); +# endif +#endif /* Do common processing for the child, such as execing the command. */ do_child(s, command); @@ -677,32 +558,68 @@ do_exec_pty(Session *s, const char *command) } else { server_loop(pid, ptyfd, fdout, -1); /* server_loop _has_ closed ptyfd and fdout. */ - session_pty_cleanup(s); } } -const char * -get_remote_name_or_ip(void) +#ifdef LOGIN_NEEDS_UTMPX +void +do_pre_login(Session *s) { - static const char *remote = ""; - if (utmp_len > 0) - remote = get_canonical_hostname(options.reverse_mapping_check); - if (utmp_len == 0 || strlen(remote) > utmp_len) - remote = get_remote_ipaddr(); - return remote; + socklen_t fromlen; + struct sockaddr_storage from; + pid_t pid = getpid(); + + /* + * Get IP address of client. If the connection is not a socket, let + * the address be 0.0.0.0. + */ + memset(&from, 0, sizeof(from)); + if (packet_connection_is_on_socket()) { + fromlen = sizeof(from); + if (getpeername(packet_get_connection_in(), + (struct sockaddr *) & from, &fromlen) < 0) { + debug("getpeername: %.100s", strerror(errno)); + fatal_cleanup(); + } + } + + record_utmp_only(pid, s->tty, s->pw->pw_name, + get_remote_name_or_ip(utmp_len, options.reverse_mapping_check), + (struct sockaddr *)&from); +} +#endif + +/* + * This is called to fork and execute a command. If another command is + * to be forced, execute that instead. + */ +void +do_exec(Session *s, const char *command) +{ + if (forced_command) { + original_command = command; + command = forced_command; + forced_command = NULL; + debug("Forced command '%.900s'", command); + } + + if (s->ttyfd != -1) + do_exec_pty(s, command); + else + do_exec_no_pty(s, command); + + original_command = NULL; } + /* administrative, login(1)-like work */ void do_login(Session *s, const char *command) { - FILE *f; char *time_string; - char buf[256]; char hostname[MAXHOSTNAMELEN]; socklen_t fromlen; struct sockaddr_storage from; - struct stat st; time_t last_login_time; struct passwd * pw = s->pw; pid_t pid = getpid(); @@ -722,13 +639,16 @@ do_login(Session *s, const char *command) } /* Get the time and hostname when the user last logged in. */ - hostname[0] = '\0'; - last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name, - hostname, sizeof(hostname)); + if (options.print_lastlog) { + hostname[0] = '\0'; + last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name, + hostname, sizeof(hostname)); + } /* 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(), (struct sockaddr *)&from); + get_remote_name_or_ip(utmp_len, options.reverse_mapping_check), + (struct sockaddr *)&from); #ifdef USE_PAM /* @@ -741,15 +661,7 @@ do_login(Session *s, const char *command) } #endif - /* Done if .hushlogin exists or a command given. */ - if (command != NULL) - return; - snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir); -#ifdef HAVE_LOGIN_CAP - if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0) -#else - if (stat(buf, &st) >= 0) -#endif + if (check_quietlogin(s, command)) return; #ifdef USE_PAM @@ -761,7 +673,7 @@ do_login(Session *s, const char *command) printf("%s\n", aixloginmsg); #endif /* WITH_AIXAUTHENTICATE */ - if (last_login_time != 0) { + if (options.print_lastlog && last_login_time != 0) { time_string = ctime(&last_login_time); if (strchr(time_string, '\n')) *strchr(time_string, '\n') = 0; @@ -770,6 +682,19 @@ do_login(Session *s, const char *command) else printf("Last login: %s from %s\r\n", time_string, hostname); } + + do_motd(); +} + +/* + * Display the message of the day. + */ +void +do_motd(void) +{ + FILE *f; + char buf[256]; + if (options.print_motd) { #ifdef HAVE_LOGIN_CAP f = fopen(login_getcapstr(lc, "welcome", "/etc/motd", @@ -785,6 +710,31 @@ do_login(Session *s, const char *command) } } + +/* + * Check for quiet login, either .hushlogin or command given. + */ +int +check_quietlogin(Session *s, const char *command) +{ + char buf[256]; + struct passwd * pw = s->pw; + struct stat st; + + /* Return 1 if .hushlogin exists or a command given. */ + if (command != NULL) + return 1; + snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir); +#ifdef HAVE_LOGIN_CAP + if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0) + return 1; +#else + if (stat(buf, &st) >= 0) + return 1; +#endif + return 0; +} + /* * Sets the value of the given variable in the environment. If the variable * already exists, its value is overriden. @@ -1019,7 +969,7 @@ do_child(Session *s, const char *command) extern char **environ; struct stat st; char *argv[10]; - int do_xauth = s->auth_proto != NULL && s->auth_data != NULL; + int do_xauth; #ifdef WITH_IRIX_PROJECT prid_t projid; #endif /* WITH_IRIX_PROJECT */ @@ -1031,11 +981,17 @@ do_child(Session *s, const char *command) #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; -#ifndef USE_PAM /* pam_nologin handles this */ +#if !defined(USE_PAM) && !defined(HAVE_OSF_SIA) if (!options.use_login) { # ifdef HAVE_LOGIN_CAP if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid) @@ -1053,7 +1009,7 @@ do_child(Session *s, const char *command) exit(254); } } -#endif /* USE_PAM */ +#endif /* USE_PAM || HAVE_OSF_SIA */ /* Set login name, uid, gid, and groups. */ /* Login(1) does this as well, and it needs uid 0 for the "-h" @@ -1061,6 +1017,8 @@ do_child(Session *s, const char *command) 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) { @@ -1076,13 +1034,6 @@ do_child(Session *s, const char *command) perror("unable to set user context"); exit(1); } -#ifdef BSD_AUTH - if (auth_approval(NULL, lc, pw->pw_name, "ssh") <= 0) { - error("approval failure for %s", pw->pw_name); - fprintf(stderr, "Approval failure"); - exit(1); - } -#endif # else /* HAVE_LOGIN_CAP */ #if defined(HAVE_GETLUID) && defined(HAVE_SETLUID) /* Sets login uid for accounting */ @@ -1102,6 +1053,15 @@ do_child(Session *s, const char *command) 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) { @@ -1155,7 +1115,7 @@ do_child(Session *s, const char *command) #endif /* Permanently switch to the desired uid. */ - permanently_set_uid(pw->pw_uid); + permanently_set_uid(pw); # endif /* HAVE_LOGIN_CAP */ } #endif /* HAVE_OSF_SIA */ @@ -1281,8 +1241,6 @@ do_child(Session *s, const char *command) do_pam_environment(&env, &envsize); #endif /* USE_PAM */ - if (xauthfile) - child_set_env(&env, &envsize, "XAUTHORITY", xauthfile); if (auth_get_socket_name() != NULL) child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, auth_get_socket_name()); @@ -1301,7 +1259,8 @@ do_child(Session *s, const char *command) } /* we have to stash the hostname before we close our socket. */ if (options.use_login) - hostname = get_remote_name_or_ip(); + hostname = get_remote_name_or_ip(utmp_len, + options.reverse_mapping_check); /* * Close the connection descriptors; note that this is the child, and * the server will still have the socket open, and it is important @@ -1358,24 +1317,25 @@ do_child(Session *s, const char *command) * in this order). */ if (!options.use_login) { - if (stat(_PATH_SSH_USER_RC, &st) >= 0) { + /* 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 %s\n", _PATH_BSHELL, - _PATH_SSH_USER_RC); - f = popen(_PATH_BSHELL " " _PATH_SSH_USER_RC, "w"); + 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", + 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) @@ -1477,6 +1437,9 @@ do_child(Session *s, const char *command) /* Launch login(1). */ execl(LOGIN_PROGRAM, "login", "-h", hostname, +#ifdef LOGIN_NEEDS_TERM + s->term? s->term : "unknown", +#endif "-p", "-f", "--", pw->pw_name, NULL); /* Login couldn't be executed, die. */ @@ -1507,27 +1470,18 @@ session_new(void) debug("session_new: init"); for(i = 0; i < MAX_SESSIONS; i++) { sessions[i].used = 0; - sessions[i].self = i; } did_init = 1; } for(i = 0; i < MAX_SESSIONS; i++) { Session *s = &sessions[i]; if (! s->used) { - s->pid = 0; - s->is_subsystem = 0; + memset(s, 0, sizeof(*s)); s->chanid = -1; s->ptyfd = -1; s->ttyfd = -1; - s->tty[0] = '\0'; - s->term = NULL; - s->pw = NULL; - s->display = NULL; - s->screen = 0; - s->auth_data = NULL; - s->auth_proto = NULL; s->used = 1; - s->pw = NULL; + s->self = i; debug("session_new: session %d", i); return s; } @@ -1614,48 +1568,64 @@ int session_pty_req(Session *s) { u_int len; - char *term_modes; /* encoded terminal modes */ + int n_bytes; - if (no_pty_flag) + if (no_pty_flag) { + debug("Allocating a pty not permitted for this authentication."); return 0; - if (s->ttyfd != -1) + } + if (s->ttyfd != -1) { + packet_disconnect("Protocol error: you already have a pty."); return 0; + } + s->term = packet_get_string(&len); - s->col = packet_get_int(); - s->row = packet_get_int(); + + if (compat20) { + s->col = packet_get_int(); + s->row = packet_get_int(); + } else { + s->row = packet_get_int(); + s->col = packet_get_int(); + } s->xpixel = packet_get_int(); s->ypixel = packet_get_int(); - term_modes = packet_get_string(&len); - packet_done(); if (strcmp(s->term, "") == 0) { xfree(s->term); s->term = NULL; } + /* Allocate a pty and open it. */ + debug("Allocating pty."); if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) { - xfree(s->term); + if (s->term) + xfree(s->term); s->term = NULL; s->ptyfd = -1; s->ttyfd = -1; error("session_pty_req: session %d alloc failed", s->self); - xfree(term_modes); return 0; } debug("session_pty_req: session %d alloc %s", s->self, s->tty); + + /* for SSH1 the tty modes length is not given */ + if (!compat20) + n_bytes = packet_remaining(); + tty_parse_modes(s->ttyfd, &n_bytes); + /* * Add a cleanup function to clear the utmp entry and record logout * time in case we call fatal() (e.g., the connection gets closed). */ - fatal_add_cleanup(pty_cleanup_proc, (void *)s); + fatal_add_cleanup(session_pty_cleanup, (void *)s); pty_setowner(s->pw, s->tty); - /* Get window size from the packet. */ + + /* Set window size from the packet. */ pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); + packet_done(); session_proctitle(s); - - /* XXX parse and set terminal modes */ - xfree(term_modes); return 1; } @@ -1689,23 +1659,7 @@ session_subsystem_req(Session *s) int session_x11_req(Session *s) { - int fd; - if (no_x11_forwarding_flag) { - debug("X11 forwarding disabled in user configuration file."); - return 0; - } - if (!options.x11_forwarding) { - debug("X11 forwarding disabled in server configuration file."); - return 0; - } - if (xauthfile != NULL) { - debug("X11 fwd already started."); - return 0; - } - - debug("Received request for X11 forwarding with auth spoofing."); - if (s->display != NULL) - packet_disconnect("Protocol error: X11 display already set."); + int success; s->single_connection = packet_get_char(); s->auth_proto = packet_get_string(NULL); @@ -1713,45 +1667,21 @@ session_x11_req(Session *s) s->screen = packet_get_int(); packet_done(); - s->display = x11_create_display_inet(s->screen, options.x11_display_offset); - if (s->display == NULL) { - xfree(s->auth_proto); - xfree(s->auth_data); - return 0; - } - xauthfile = xmalloc(MAXPATHLEN); - strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN); - temporarily_use_uid(s->pw->pw_uid); - if (mkdtemp(xauthfile) == NULL) { - restore_uid(); - error("private X11 dir: mkdtemp %s failed: %s", - xauthfile, strerror(errno)); - xfree(xauthfile); - xauthfile = NULL; + success = session_setup_x11fwd(s); + if (!success) { xfree(s->auth_proto); xfree(s->auth_data); - /* XXXX remove listening channels */ - return 0; + s->auth_proto = NULL; + s->auth_data = NULL; } - strlcat(xauthfile, "/cookies", MAXPATHLEN); - fd = open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600); - if (fd >= 0) - close(fd); - restore_uid(); - fatal_add_cleanup(xauthfile_cleanup_proc, s); - return 1; + return success; } int session_shell_req(Session *s) { - /* if forced_command == NULL, the shell is execed */ - char *shell = forced_command; packet_done(); - if (s->ttyfd == -1) - do_exec_no_pty(s, shell); - else - do_exec_pty(s, shell); + do_exec(s, NULL); return 1; } @@ -1761,17 +1691,8 @@ session_exec_req(Session *s) u_int len; char *command = packet_get_string(&len); packet_done(); - if (forced_command) { - original_command = command; - command = forced_command; - debug("Forced command '%.500s'", forced_command); - } - if (s->ttyfd == -1) - do_exec_no_pty(s, command); - else - do_exec_pty(s, command); - if (forced_command == NULL) - xfree(command); + do_exec(s, command); + xfree(command); return 1; } @@ -1864,19 +1785,27 @@ session_set_fds(Session *s, int fdin, int fdout, int fderr) 1); } +/* + * Function to perform pty cleanup. Also called if we get aborted abnormally + * (e.g., due to a dropped connection). + */ void -session_pty_cleanup(Session *s) +session_pty_cleanup(void *session) { - if (s == NULL || s->ttyfd == -1) + Session *s = session; + + if (s == NULL) { + error("session_pty_cleanup: no session"); + return; + } + if (s->ttyfd == -1) return; debug("session_pty_cleanup: session %d release %s", s->self, s->tty); - /* Cancel the cleanup function. */ - fatal_remove_cleanup(pty_cleanup_proc, (void *)s); - /* Record that the user has logged out. */ - record_logout(s->pid, s->tty); + if (s->pid != 0) + record_logout(s->pid, s->tty); /* Release the pseudo-tty. */ pty_release(s->tty); @@ -1898,7 +1827,7 @@ session_exit_message(Session *s, int status) fatal("session_close: no session"); c = channel_lookup(s->chanid); if (c == NULL) - fatal("session_close: session %d: no channel %d", + 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); @@ -1940,9 +1869,13 @@ session_exit_message(Session *s, int status) } void -session_free(Session *s) +session_close(Session *s) { - debug("session_free: session %d pid %d", s->self, s->pid); + debug("session_close: session %d pid %d", s->self, s->pid); + if (s->ttyfd != -1) { + fatal_remove_cleanup(session_pty_cleanup, (void *)s); + session_pty_cleanup(s); + } if (s->term) xfree(s->term); if (s->display) @@ -1952,13 +1885,6 @@ session_free(Session *s) if (s->auth_proto) xfree(s->auth_proto); s->used = 0; -} - -void -session_close(Session *s) -{ - session_pty_cleanup(s); - session_free(s); session_proctitle(s); } @@ -1967,7 +1893,7 @@ session_close_by_pid(pid_t pid, int status) { Session *s = session_by_pid(pid); if (s == NULL) { - debug("session_close_by_pid: no session for pid %d", s->pid); + debug("session_close_by_pid: no session for pid %d", pid); return; } if (s->chanid != -1) @@ -2031,11 +1957,43 @@ session_proctitle(Session *s) setproctitle("%s@%s", s->pw->pw_name, session_tty_list()); } +int +session_setup_x11fwd(Session *s) +{ + struct stat st; + + if (no_x11_forwarding_flag) { + packet_send_debug("X11 forwarding disabled in user configuration file."); + return 0; + } + if (!options.x11_forwarding) { + debug("X11 forwarding disabled in server configuration file."); + return 0; + } + if (!options.xauth_location || + (stat(options.xauth_location, &st) == -1)) { + packet_send_debug("No xauth program; cannot forward with spoofing."); + return 0; + } + if (options.use_login) { + packet_send_debug("X11 forwarding disabled; " + "not compatible with UseLogin=yes."); + return 0; + } + if (s->display != NULL) { + debug("X11 display already set."); + return 0; + } + s->display = x11_create_display_inet(s->screen, options.x11_display_offset); + if (s->display == NULL) { + debug("x11_create_display_inet failed."); + return 0; + } + return 1; +} + void do_authenticated2(Authctxt *authctxt) { - server_loop2(); - if (xauthfile) - xauthfile_cleanup_proc(NULL); }