diff options
Diffstat (limited to 'crypto/openssh/session.c')
-rw-r--r-- | crypto/openssh/session.c | 305 |
1 files changed, 192 insertions, 113 deletions
diff --git a/crypto/openssh/session.c b/crypto/openssh/session.c index eddcf6c..2992794 100644 --- a/crypto/openssh/session.c +++ b/crypto/openssh/session.c @@ -33,7 +33,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: session.c,v 1.128 2002/02/16 00:51:44 markus Exp $"); +RCSID("$OpenBSD: session.c,v 1.138 2002/06/20 23:05:55 markus Exp $"); RCSID("$FreeBSD$"); #include "ssh.h" @@ -57,6 +57,7 @@ RCSID("$FreeBSD$"); #include "serverloop.h" #include "canohost.h" #include "session.h" +#include "monitor_wrap.h" #ifdef __FreeBSD__ #define _PATH_CHPASS "/usr/bin/passwd" @@ -69,39 +70,11 @@ RCSID("$FreeBSD$"); #include <login_cap.h> #endif -/* types */ - -#define TTYSZ 64 -typedef struct Session Session; -struct Session { - int used; - int self; - struct passwd *pw; - Authctxt *authctxt; - pid_t pid; - /* tty */ - char *term; - int ptyfd, ttyfd, ptymaster; - int row, col, xpixel, ypixel; - char tty[TTYSZ]; - /* X11 */ - int display_number; - char *display; - int screen; - char *auth_display; - char *auth_proto; - char *auth_data; - int single_connection; - /* proto 2 */ - int chanid; - int is_subsystem; -}; - /* func */ Session *session_new(void); void session_set_fds(Session *, int, int, int); -static void session_pty_cleanup(void *); +void session_pty_cleanup(void *); void session_proctitle(Session *); int session_setup_x11fwd(Session *); void do_exec_pty(Session *, const char *); @@ -115,7 +88,6 @@ int check_quietlogin(Session *, const char *); static void do_authenticated1(Authctxt *); static void do_authenticated2(Authctxt *); -static void session_close(Session *); static int session_pty_req(Session *); /* import */ @@ -135,9 +107,96 @@ const char *original_command = NULL; Session sessions[MAX_SESSIONS]; #ifdef HAVE_LOGIN_CAP -static login_cap_t *lc; +login_cap_t *lc; #endif +/* Name and directory of socket for authentication agent forwarding. */ +static char *auth_sock_name = NULL; +static char *auth_sock_dir = NULL; + +/* removes the agent forwarding socket */ + +static void +auth_sock_cleanup_proc(void *_pw) +{ + struct passwd *pw = _pw; + + if (auth_sock_name != NULL) { + temporarily_use_uid(pw); + unlink(auth_sock_name); + rmdir(auth_sock_dir); + auth_sock_name = NULL; + restore_uid(); + } +} + +static int +auth_input_request_forwarding(struct passwd * pw) +{ + Channel *nc; + int sock; + struct sockaddr_un sunaddr; + + if (auth_sock_name != NULL) { + error("authentication forwarding requested twice."); + return 0; + } + + /* Temporarily drop privileged uid for mkdir/bind. */ + temporarily_use_uid(pw); + + /* Allocate a buffer for the socket name, and format the name. */ + auth_sock_name = xmalloc(MAXPATHLEN); + auth_sock_dir = xmalloc(MAXPATHLEN); + strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXX", MAXPATHLEN); + + /* Create private directory for socket */ + if (mkdtemp(auth_sock_dir) == NULL) { + packet_send_debug("Agent forwarding disabled: " + "mkdtemp() failed: %.100s", strerror(errno)); + restore_uid(); + xfree(auth_sock_name); + xfree(auth_sock_dir); + auth_sock_name = NULL; + auth_sock_dir = NULL; + return 0; + } + snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld", + auth_sock_dir, (long) getpid()); + + /* delete agent socket on fatal() */ + fatal_add_cleanup(auth_sock_cleanup_proc, pw); + + /* Create the socket. */ + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + packet_disconnect("socket: %.100s", strerror(errno)); + + /* Bind it to the name. */ + memset(&sunaddr, 0, sizeof(sunaddr)); + 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) + packet_disconnect("bind: %.100s", strerror(errno)); + + /* Restore the privileged uid. */ + restore_uid(); + + /* Start listening on the socket. */ + if (listen(sock, 5) < 0) + packet_disconnect("listen: %.100s", strerror(errno)); + + /* Allocate a channel for the authentication agent socket. */ + nc = channel_new("auth socket", + SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, + CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, + 0, xstrdup("auth socket"), 1); + strlcpy(nc->path, auth_sock_name, sizeof(nc->path)); + return 1; +} + + void do_authenticated(Authctxt *authctxt) { @@ -150,18 +209,6 @@ do_authenticated(Authctxt *authctxt) close(startup_pipe); startup_pipe = -1; } -#ifdef HAVE_LOGIN_CAP - if ((lc = login_getpwclass(authctxt->pw)) == 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 /* setup the channel layer */ if (!no_port_forwarding_flag && options.allow_tcp_forwarding) channel_permit_all_opens(); @@ -172,7 +219,7 @@ do_authenticated(Authctxt *authctxt) do_authenticated1(authctxt); /* remove agent socket */ - if (auth_get_socket_name()) + if (auth_sock_name != NULL) auth_sock_cleanup_proc(authctxt->pw); #ifdef KRB4 if (options.kerberos_ticket_cleanup) @@ -223,6 +270,10 @@ do_authenticated1(Authctxt *authctxt) compression_level); break; } + if (!options.compression) { + debug2("compression disabled"); + break; + } /* Enable compression after we have responded with SUCCESS. */ enable_compression_after_reply = 1; success = 1; @@ -379,7 +430,7 @@ do_authenticated1(Authctxt *authctxt) void do_exec_no_pty(Session *s, const char *command) { - int pid; + pid_t pid; #ifdef USE_PIPES int pin[2], pout[2], perr[2]; @@ -603,22 +654,13 @@ do_exec(Session *s, const char *command) void do_login(Session *s, const char *command) { - FILE *f; #ifndef USE_PAM char *time_string; - char *newcommand = NULL; #endif - char buf[256]; -#ifndef USE_PAM - char hostname[MAXHOSTNAMELEN]; socklen_t fromlen; struct sockaddr_storage from; - time_t last_login_time; -#endif struct passwd * pw = s->pw; -#ifndef USE_PAM pid_t pid = getpid(); -#endif #ifdef __FreeBSD__ #define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */ struct timeval tv; @@ -644,20 +686,6 @@ do_login(Session *s, const char *command) } #endif -#ifndef USE_PAM - /* Get the time and hostname when the user last logged in. */ - 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(utmp_len, options.verify_reverse_mapping), - (struct sockaddr *)&from); -#endif - #ifdef USE_PAM /* * If password change is needed, do it now. @@ -729,6 +757,13 @@ do_login(Session *s, const char *command) } #endif /* HAVE_LOGIN_CAP */ + /* Record that there was a login on that tty from the remote host. */ + if (!use_privsep) + record_login(pid, s->tty, pw->pw_name, pw->pw_uid, + get_remote_name_or_ip(utmp_len, + options.verify_reverse_mapping), + (struct sockaddr *)&from); + #ifdef USE_PAM if (command == NULL && options.print_lastlog && !check_quietlogin(s, command) && @@ -745,22 +780,27 @@ do_login(Session *s, const char *command) */ if (command == NULL && options.print_lastlog && - last_login_time != 0 && !check_quietlogin(s, command) && + s->last_login_time != 0 && !check_quietlogin(s, command) && !options.use_login) { - time_string = ctime(&last_login_time); + time_string = ctime(&s->last_login_time); if (strchr(time_string, '\n')) *strchr(time_string, '\n') = 0; - if (strcmp(hostname, "") == 0) + if (strcmp(s->hostname, "") == 0) printf("Last login: %s\r\n", time_string); else - printf("Last login: %s from %s\r\n", time_string, hostname); + printf("Last login: %s from %s\r\n", time_string, + s->hostname); } #endif /* !USE_PAM */ if (command == NULL && !check_quietlogin(s, command) && !options.use_login) { #ifdef HAVE_LOGIN_CAP - const char *fname = login_getcapstr(lc, "copyright", NULL, NULL); + const char *fname; + char buf[256]; + FILE *f; + + fname = login_getcapstr(lc, "copyright", NULL, NULL); if (fname != NULL && (f = fopen(fname, "r")) != NULL) { while (fgets(buf, sizeof(buf), f) != NULL) fputs(buf, stdout); @@ -1033,9 +1073,9 @@ do_setup_env(char **env, Session *s, const char *shell) do_pam_environment(&env, &envsize); #endif /* USE_PAM */ - if (auth_get_socket_name() != NULL) + if (auth_sock_name != NULL) child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, - auth_get_socket_name()); + auth_sock_name); /* read $HOME/.ssh/environment. */ if (!options.use_login) { @@ -1099,7 +1139,7 @@ do_rc_files(Session *s, const char *shell) /* Add authority data to .Xauthority if appropriate. */ if (debug_flag) { fprintf(stderr, - "Running %.100s add " + "Running %.500s add " "%.100s %.100s %.100s\n", options.xauth_location, s->auth_display, s->auth_proto, s->auth_data); @@ -1143,11 +1183,10 @@ do_nologin(struct passwd *pw) } /* Set login name, uid, gid, and groups. */ -static char ** -do_setusercontext(Session *s) +void +do_setusercontext(struct passwd *pw) { char **env = NULL; - struct passwd *pw = s->pw; #ifdef HAVE_LOGIN_CAP char buf[256]; char **tmpenv; @@ -1170,9 +1209,6 @@ do_setusercontext(Session *s) if (getenv("TZ")) child_set_env(&env, &envsize, "TZ", getenv("TZ")); - if (s->term) - child_set_env(&env, &envsize, "TERM", s->term); - /* Save parent environment */ tmpenv = environ; /* Switch to env */ @@ -1207,7 +1243,21 @@ do_setusercontext(Session *s) if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) fatal("Failed to set uids to %u.", (u_int) pw->pw_uid); #endif /* HAVE_LOGIN_CAP */ - return env; + return; +} + +static void +launch_login(struct passwd *pw, const char *hostname) +{ + /* Launch login(1). */ + + execl("/usr/bin/login", "login", "-h", hostname, + "-p", "-f", "--", pw->pw_name, (char *)NULL); + + /* Login couldn't be executed, die. */ + + perror("login"); + exit(1); } /* @@ -1242,7 +1292,7 @@ do_child(Session *s, const char *command) */ if (!options.use_login) { do_nologin(pw); - env = do_setusercontext(s); + do_setusercontext(pw); } /* @@ -1336,15 +1386,8 @@ do_child(Session *s, const char *command) signal(SIGPIPE, SIG_DFL); if (options.use_login) { - /* Launch login(1). */ - - execl("/usr/bin/login", "login", "-h", hostname, - "-p", "-f", "--", pw->pw_name, (char *)NULL); - - /* Login couldn't be executed, die. */ - - perror("login"); - exit(1); + launch_login(pw, hostname); + /* NEVERREACHED */ } /* Get the last component of the shell name. */ @@ -1450,12 +1493,12 @@ session_dump(void) int i; for (i = 0; i < MAX_SESSIONS; i++) { Session *s = &sessions[i]; - debug("dump: used %d session %d %p channel %d pid %d", + debug("dump: used %d session %d %p channel %d pid %ld", s->used, s->self, s, s->chanid, - s->pid); + (long)s->pid); } } @@ -1477,6 +1520,22 @@ session_open(Authctxt *authctxt, int chanid) return 1; } +Session * +session_by_tty(char *tty) +{ + int i; + for (i = 0; i < MAX_SESSIONS; i++) { + Session *s = &sessions[i]; + if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) { + debug("session_by_tty: session %d tty %s", i, tty); + return s; + } + } + debug("session_by_tty: unknown tty %.100s", tty); + session_dump(); + return NULL; +} + static Session * session_by_channel(int id) { @@ -1497,13 +1556,13 @@ static Session * session_by_pid(pid_t pid) { int i; - debug("session_by_pid: pid %d", pid); + debug("session_by_pid: pid %ld", (long)pid); for (i = 0; i < MAX_SESSIONS; i++) { Session *s = &sessions[i]; if (s->used && s->pid == pid) return s; } - error("session_by_pid: unknown pid %d", pid); + error("session_by_pid: unknown pid %ld", (long)pid); session_dump(); return NULL; } @@ -1534,6 +1593,12 @@ session_pty_req(Session *s) packet_disconnect("Protocol error: you already have a pty."); return 0; } + /* Get the time and hostname when the user last logged in. */ + if (options.print_lastlog) { + s->hostname[0] = '\0'; + s->last_login_time = get_last_login_time(s->pw->pw_uid, + s->pw->pw_name, s->hostname, sizeof(s->hostname)); + } s->term = packet_get_string(&len); @@ -1554,7 +1619,7 @@ session_pty_req(Session *s) /* Allocate a pty and open it. */ debug("Allocating pty."); - if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) { + if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)))) { if (s->term) xfree(s->term); s->term = NULL; @@ -1575,7 +1640,8 @@ session_pty_req(Session *s) * time in case we call fatal() (e.g., the connection gets closed). */ fatal_add_cleanup(session_pty_cleanup, (void *)s); - pty_setowner(s->pw, s->tty); + if (!use_privsep) + pty_setowner(s->pw, s->tty); /* Set window size from the packet. */ pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); @@ -1738,8 +1804,8 @@ session_set_fds(Session *s, int fdin, int fdout, int fderr) * Function to perform pty cleanup. Also called if we get aborted abnormally * (e.g., due to a dropped connection). */ -static void -session_pty_cleanup(void *session) +void +session_pty_cleanup2(void *session) { Session *s = session; @@ -1757,7 +1823,8 @@ session_pty_cleanup(void *session) record_logout(s->pid, s->tty); /* Release the pseudo-tty. */ - pty_release(s->tty); + if (getuid() == 0) + pty_release(s->tty); /* * Close the server side of the socket pairs. We must do this after @@ -1765,12 +1832,18 @@ session_pty_cleanup(void *session) * while we're still cleaning up. */ if (close(s->ptymaster) < 0) - error("close(s->ptymaster): %s", strerror(errno)); + error("close(s->ptymaster/%d): %s", s->ptymaster, strerror(errno)); /* unlink pty from session */ s->ttyfd = -1; } +void +session_pty_cleanup(void *session) +{ + PRIVSEP(session_pty_cleanup2(session)); +} + static void session_exit_message(Session *s, int status) { @@ -1779,8 +1852,8 @@ session_exit_message(Session *s, int status) 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); + debug("session_exit_message: session %d channel %d pid %ld", + s->self, s->chanid, (long)s->pid); if (WIFEXITED(status)) { channel_request_start(s->chanid, "exit-status", 0); @@ -1812,10 +1885,10 @@ session_exit_message(Session *s, int status) s->chanid = -1; } -static void +void session_close(Session *s) { - debug("session_close: session %d pid %d", s->self, s->pid); + debug("session_close: session %d pid %ld", s->self, (long)s->pid); if (s->ttyfd != -1) { fatal_remove_cleanup(session_pty_cleanup, (void *)s); session_pty_cleanup(s); @@ -1839,7 +1912,8 @@ 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", pid); + debug("session_close_by_pid: no session for pid %ld", + (long)pid); return; } if (s->chanid != -1) @@ -1859,7 +1933,8 @@ session_close_by_channel(int id, void *arg) debug("session_close_by_channel: no session for id %d", id); return; } - debug("session_close_by_channel: channel %d child %d", id, s->pid); + debug("session_close_by_channel: channel %d child %ld", + id, (long)s->pid); if (s->pid != 0) { debug("session_close_by_channel: channel %d: has child", id); /* @@ -1879,13 +1954,17 @@ session_close_by_channel(int id, void *arg) } void -session_destroy_all(void) +session_destroy_all(void (*closefunc)(Session *)) { int i; for (i = 0; i < MAX_SESSIONS; i++) { Session *s = &sessions[i]; - if (s->used) - session_close(s); + if (s->used) { + if (closefunc != NULL) + closefunc(s); + else + session_close(s); + } } } |