=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/session.c,v retrieving revision 1.12 retrieving revision 1.12.2.4 diff -u -r1.12 -r1.12.2.4 --- src/usr.bin/ssh/session.c 2000/05/03 18:03:07 1.12 +++ src/usr.bin/ssh/session.c 2001/03/12 15:44:14 1.12.2.4 @@ -1,32 +1,67 @@ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved - */ -/* + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + * * SSH2 support by Markus Friedl. * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$OpenBSD: session.c,v 1.12 2000/05/03 18:03:07 markus Exp $"); +RCSID("$OpenBSD: session.c,v 1.12.2.4 2001/03/12 15:44:14 jason Exp $"); -#include "xmalloc.h" #include "ssh.h" +#include "ssh1.h" +#include "ssh2.h" +#include "xmalloc.h" #include "pty.h" #include "packet.h" #include "buffer.h" -#include "cipher.h" #include "mpaux.h" -#include "servconf.h" #include "uidswap.h" #include "compat.h" #include "channels.h" #include "nchan.h" - #include "bufaux.h" -#include "ssh2.h" #include "auth.h" +#include "auth-options.h" +#include "pathnames.h" +#include "log.h" +#include "servconf.h" +#include "login.h" +#include "serverloop.h" +#include "canohost.h" +#include "session.h" +#ifdef HAVE_LOGIN_CAP +#include +#endif + /* types */ #define TTYSZ 64 @@ -60,6 +95,7 @@ void session_proctitle(Session *s); void do_exec_pty(Session *s, const char *command, struct passwd * pw); void do_exec_no_pty(Session *s, const char *command, struct passwd * pw); +void do_login(Session *s, const char *command); void do_child(const char *command, struct passwd * pw, const char *term, @@ -71,26 +107,24 @@ 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; +/* original command from peer. */ +char *original_command = NULL; + /* data */ #define MAX_SESSIONS 10 Session sessions[MAX_SESSIONS]; -/* Flags set in auth-rsa from authorized_keys flags. These are set in auth-rsa.c. */ -int no_port_forwarding_flag = 0; -int no_agent_forwarding_flag = 0; -int no_x11_forwarding_flag = 0; -int no_pty_flag = 0; +#ifdef HAVE_LOGIN_CAP +static login_cap_t *lc; +#endif -/* RSA authentication "command=" option. */ -char *forced_command = NULL; - -/* RSA authentication "environment=" options. */ -struct envstring *custom_environment = NULL; - /* * Remove local Xauthority file. */ @@ -143,19 +177,23 @@ do_authenticated(struct passwd * pw) { Session *s; - int type; + int type, fd; int compression_level = 0, enable_compression_after_reply = 0; int have_pty = 0; char *command; int n_bytes; int plen; - unsigned int proto_len, data_len, dlen; + u_int proto_len, data_len, dlen; /* * Cancel the alarm we set to limit the time taken for * authentication. */ alarm(0); + if (startup_pipe != -1) { + close(startup_pipe); + startup_pipe = -1; + } /* * Inform the channel mechanism that we are the server side and that @@ -164,12 +202,19 @@ * by the client telling us, so we can equally well trust the client * not to request anything bogus.) */ - if (!no_port_forwarding_flag) + if (!no_port_forwarding_flag && options.allow_tcp_forwarding) channel_permit_all_opens(); s = session_new(); s->pw = pw; +#ifdef HAVE_LOGIN_CAP + if ((lc = login_getclass(pw->pw_class)) == NULL) { + error("unable to get login class"); + return; + } +#endif + /* * We stay in this loop until the client requests to execute a shell * or a command. @@ -248,7 +293,10 @@ packet_send_debug("X11 forwarding disabled in server configuration file."); break; } -#ifdef XAUTH_PATH + 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; @@ -259,12 +307,18 @@ s->auth_proto = packet_get_string(&proto_len); s->auth_data = packet_get_string(&data_len); - packet_integrity_check(plen, 4 + proto_len + 4 + data_len + 4, type); - if (packet_get_protocol_flags() & SSH_PROTOFLAG_SCREEN_NUMBER) + if (packet_get_protocol_flags() & SSH_PROTOFLAG_SCREEN_NUMBER) { + debug2("SSH_PROTOFLAG_SCREEN_NUMBER == true"); + packet_integrity_check(plen, + 4 + proto_len + 4 + data_len + 4, type); s->screen = packet_get_int(); - else + } else { + debug2("SSH_PROTOFLAG_SCREEN_NUMBER == false"); + 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) @@ -284,15 +338,13 @@ break; } strlcat(xauthfile, "/cookies", MAXPATHLEN); - open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600); + 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; -#else /* XAUTH_PATH */ - packet_send_debug("No xauth program; cannot forward with spoofing."); - break; -#endif /* XAUTH_PATH */ case SSH_CMSG_AGENT_REQUEST_FORWARDING: if (no_agent_forwarding_flag || compat13) { @@ -300,8 +352,7 @@ break; } debug("Received authentication agent forwarding request."); - auth_input_request_forwarding(pw); - success = 1; + success = auth_input_request_forwarding(pw); break; case SSH_CMSG_PORT_FORWARD_REQUEST: @@ -309,6 +360,10 @@ debug("Port forwarding not permitted for this authentication."); break; } + if (!options.allow_tcp_forwarding) { + debug("Port forwarding not permitted."); + break; + } debug("Received TCP/IP port forwarding request."); channel_input_port_forward_request(pw->pw_uid == 0, options.gateway_ports); success = 1; @@ -321,10 +376,6 @@ case SSH_CMSG_EXEC_SHELL: case SSH_CMSG_EXEC_CMD: - /* Set interactive/non-interactive mode. */ - packet_set_interactive(have_pty || s->display != NULL, - options.keepalives); - if (type == SSH_CMSG_EXEC_CMD) { command = packet_get_string(&dlen); debug("Exec command '%.500s'", command); @@ -334,6 +385,7 @@ packet_integrity_check(plen, 0, type); } if (forced_command != NULL) { + original_command = command; command = forced_command; debug("Forced command '%.500s'", forced_command); } @@ -453,6 +505,8 @@ if (pid < 0) packet_disconnect("fork failed: %.100s", strerror(errno)); s->pid = pid; + /* Set interactive/non-interactive mode. */ + packet_set_interactive(s->display != NULL); #ifdef USE_PIPES /* We are the parent. Close the child sides of the pipes. */ close(pin[0]); @@ -493,41 +547,17 @@ void do_exec_pty(Session *s, const char *command, struct passwd * pw) { - FILE *f; - char buf[100], *time_string; - char line[256]; - const char *hostname; int fdout, ptyfd, ttyfd, ptymaster; - int quiet_login; pid_t pid; - socklen_t fromlen; - struct sockaddr_storage from; - struct stat st; - time_t last_login_time; if (s == NULL) fatal("do_exec_pty: no session"); ptyfd = s->ptyfd; ttyfd = s->ttyfd; - /* Get remote host name. */ - hostname = get_canonical_hostname(); - - /* - * Get the time when the user last logged in. Buf will be set to - * contain the hostname the last login was from. - */ - if (!options.use_login) { - last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name, - buf, sizeof(buf)); - } - /* Fork the child. */ if ((pid = fork()) == 0) { - pid = getpid(); - - /* Child. Reinitialize the log because the pid has - changed. */ + /* Child. Reinitialize the log because the pid has changed. */ log_init(__progname, options.log_level, options.log_facility, log_stderr); /* Close the master side of the pseudo tty. */ @@ -551,69 +581,13 @@ /* Close the extra descriptor for the pseudo tty. */ close(ttyfd); -/* XXXX ? move to do_child() ??*/ - /* - * Get IP address of client. This is needed because we want - * to record where the user logged in from. If the - * connection is not a socket, let the ip 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 that there was a login on that terminal. */ - record_login(pid, s->tty, pw->pw_name, pw->pw_uid, hostname, - (struct sockaddr *)&from); + /* record login, etc. similar to login(1) */ + if (!(options.use_login && command == NULL)) + do_login(s, command); - /* Check if .hushlogin exists. */ - snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir); - quiet_login = stat(line, &st) >= 0; - - /* - * If the user has logged in before, display the time of last - * login. However, don't display anything extra if a command - * has been specified (so that ssh can be used to execute - * commands on a remote machine without users knowing they - * are going to another machine). Login(1) will do this for - * us as well, so check if login(1) is used - */ - if (command == NULL && last_login_time != 0 && !quiet_login && - !options.use_login) { - /* Convert the date to a string. */ - time_string = ctime(&last_login_time); - /* Remove the trailing newline. */ - if (strchr(time_string, '\n')) - *strchr(time_string, '\n') = 0; - /* Display the last login time. Host if displayed - if known. */ - if (strcmp(buf, "") == 0) - printf("Last login: %s\r\n", time_string); - else - printf("Last login: %s from %s\r\n", time_string, buf); - } - /* - * Print /etc/motd unless a command was specified or printing - * it was disabled in server options or login(1) will be - * used. Note that some machines appear to print it in - * /etc/profile or similar. - */ - if (command == NULL && options.print_motd && !quiet_login && - !options.use_login) { - /* Print /etc/motd if it exists. */ - f = fopen("/etc/motd", "r"); - if (f) { - while (fgets(line, sizeof(line), f)) - fputs(line, stdout); - fclose(f); - } - } /* Do common processing for the child, such as execing the command. */ - do_child(command, pw, s->term, s->display, s->auth_proto, s->auth_data, s->tty); + do_child(command, pw, s->term, s->display, s->auth_proto, + s->auth_data, s->tty); /* NOTREACHED */ } if (pid < 0) @@ -639,6 +613,7 @@ s->ptymaster = ptymaster; /* Enter interactive session. */ + packet_set_interactive(1); if (compat20) { session_set_fds(s, ptyfd, fdout, -1); } else { @@ -648,15 +623,98 @@ } } +const char * +get_remote_name_or_ip(void) +{ + 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; +} + +/* 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(); + + /* + * 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(); + } + } + + /* 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)); + + /* 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); + + /* 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 + return; + if (last_login_time != 0) { + time_string = ctime(&last_login_time); + if (strchr(time_string, '\n')) + *strchr(time_string, '\n') = 0; + if (strcmp(hostname, "") == 0) + printf("Last login: %s\r\n", time_string); + else + printf("Last login: %s from %s\r\n", time_string, hostname); + } + if (options.print_motd) { +#ifdef HAVE_LOGIN_CAP + f = fopen(login_getcapstr(lc, "welcome", "/etc/motd", + "/etc/motd"), "r"); +#else + f = fopen("/etc/motd", "r"); +#endif + if (f) { + while (fgets(buf, sizeof(buf), f)) + fputs(buf, stdout); + fclose(f); + } + } +} + /* * Sets the value of the given variable in the environment. If the variable * already exists, its value is overriden. */ void -child_set_env(char ***envp, unsigned int *envsizep, const char *name, +child_set_env(char ***envp, u_int *envsizep, const char *name, const char *value) { - unsigned int i, namelen; + u_int i, namelen; char **env; /* @@ -694,7 +752,7 @@ * and assignments of the form name=value. No other forms are allowed. */ void -read_environment_file(char ***env, unsigned int *envsize, +read_environment_file(char ***env, u_int *envsize, const char *filename) { FILE *f; @@ -717,7 +775,10 @@ fprintf(stderr, "Bad line in %.100s: %.200s\n", filename, buf); continue; } - /* Replace the equals sign by nul, and advance value to the value string. */ + /* + * Replace the equals sign by nul, and advance value to + * the value string. + */ *value = '\0'; value++; child_set_env(env, envsize, cp, value); @@ -735,33 +796,52 @@ const char *display, const char *auth_proto, const char *auth_data, const char *ttyname) { - const char *shell, *cp = NULL; + const char *shell, *hostname = NULL, *cp = NULL; char buf[256]; - FILE *f; - unsigned int envsize, i; + char cmd[1024]; + FILE *f = NULL; + u_int envsize, i; char **env; extern char **environ; struct stat st; char *argv[10]; - f = fopen("/etc/nologin", "r"); - if (f) { - /* /etc/nologin exists. Print its contents and exit. */ - while (fgets(buf, sizeof(buf), f)) - fputs(buf, stderr); - fclose(f); - if (pw->pw_uid != 0) + /* login(1) is only called if we execute the login shell */ + if (options.use_login && command != NULL) + options.use_login = 0; + + 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 + 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 in the kernel. */ - if (setlogin(pw->pw_name) < 0) - error("setlogin failed: %s", strerror(errno)); - - /* Set uid, gid, and groups. */ + /* 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) { if (getuid() == 0 || geteuid() == 0) { +#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 (setlogin(pw->pw_name) < 0) + error("setlogin failed: %s", strerror(errno)); if (setgid(pw->pw_gid) < 0) { perror("setgid"); exit(1); @@ -775,15 +855,19 @@ /* Permanently switch to the desired uid. */ permanently_set_uid(pw->pw_uid); +#endif } if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) - fatal("Failed to set uids to %d.", (int) 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 #ifdef AFS /* Try to get AFS tokens for the local cell. */ @@ -807,7 +891,12 @@ child_set_env(&env, &envsize, "USER", pw->pw_name); child_set_env(&env, &envsize, "LOGNAME", pw->pw_name); child_set_env(&env, &envsize, "HOME", pw->pw_dir); +#ifdef HAVE_LOGIN_CAP + (void) setusercontext(lc, pw, pw->pw_uid, LOGIN_SETPATH); + child_set_env(&env, &envsize, "PATH", getenv("PATH")); +#else child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); +#endif snprintf(buf, sizeof buf, "%.200s/%.50s", _PATH_MAILDIR, pw->pw_name); @@ -844,6 +933,9 @@ child_set_env(&env, &envsize, "TERM", term); if (display) child_set_env(&env, &envsize, "DISPLAY", display); + if (original_command) + child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND", + original_command); #ifdef KRB4 { @@ -862,7 +954,8 @@ /* read $HOME/.ssh/environment. */ if (!options.use_login) { - snprintf(buf, sizeof buf, "%.200s/.ssh/environment", pw->pw_dir); + snprintf(buf, sizeof buf, "%.200s/.ssh/environment", + pw->pw_dir); read_environment_file(&env, &envsize, buf); } if (debug_flag) { @@ -871,6 +964,9 @@ for (i = 0; env[i]; i++) fprintf(stderr, " %.200s\n", env[i]); } + /* we have to stash the hostname before we close our socket. */ + if (options.use_login) + hostname = get_remote_name_or_ip(); /* * Close the connection descriptors; note that this is the child, and * the server will still have the socket open, and it is important @@ -907,9 +1003,14 @@ close(i); /* Change current directory to the user\'s home directory. */ - if (chdir(pw->pw_dir) < 0) + if (chdir(pw->pw_dir) < 0) { fprintf(stderr, "Could not chdir to home directory %s: %s\n", pw->pw_dir, strerror(errno)); +#ifdef HAVE_LOGIN_CAP + if (login_getcapbool(lc, "requirehome", 0)) + exit(1); +#endif + } /* * Must take new environment into use so that .ssh/rc, /etc/sshrc and @@ -922,47 +1023,60 @@ * in this order). */ if (!options.use_login) { - if (stat(SSH_USER_RC, &st) >= 0) { + if (stat(_PATH_SSH_USER_RC, &st) >= 0) { if (debug_flag) - fprintf(stderr, "Running /bin/sh %s\n", SSH_USER_RC); + fprintf(stderr, "Running %s %s\n", _PATH_BSHELL, _PATH_SSH_USER_RC); - f = popen("/bin/sh " SSH_USER_RC, "w"); + f = popen(_PATH_BSHELL " " _PATH_SSH_USER_RC, "w"); if (f) { if (auth_proto != NULL && auth_data != NULL) fprintf(f, "%s %s\n", auth_proto, auth_data); pclose(f); } else - fprintf(stderr, "Could not run %s\n", SSH_USER_RC); - } else if (stat(SSH_SYSTEM_RC, &st) >= 0) { + 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 /bin/sh %s\n", SSH_SYSTEM_RC); + fprintf(stderr, "Running %s %s\n", _PATH_BSHELL, _PATH_SSH_SYSTEM_RC); - f = popen("/bin/sh " SSH_SYSTEM_RC, "w"); + f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w"); if (f) { if (auth_proto != NULL && auth_data != NULL) fprintf(f, "%s %s\n", auth_proto, auth_data); pclose(f); } else - fprintf(stderr, "Could not run %s\n", SSH_SYSTEM_RC); - } -#ifdef XAUTH_PATH - else { + fprintf(stderr, "Could not run %s\n", _PATH_SSH_SYSTEM_RC); + } else if (options.xauth_location != NULL) { /* Add authority data to .Xauthority if appropriate. */ if (auth_proto != NULL && auth_data != NULL) { - if (debug_flag) - fprintf(stderr, "Running %.100s add %.100s %.100s %.100s\n", - XAUTH_PATH, display, auth_proto, auth_data); - - f = popen(XAUTH_PATH " -q -", "w"); + char *screen = strchr(display, ':'); + if (debug_flag) { + fprintf(stderr, + "Running %.100s add %.100s %.100s %.100s\n", + options.xauth_location, display, + auth_proto, auth_data); + if (screen != NULL) + fprintf(stderr, + "Adding %.*s/unix%s %s %s\n", + (int)(screen-display), display, + screen, auth_proto, auth_data); + } + snprintf(cmd, sizeof cmd, "%s -q -", + options.xauth_location); + f = popen(cmd, "w"); if (f) { - fprintf(f, "add %s %s %s\n", display, auth_proto, auth_data); + fprintf(f, "add %s %s %s\n", display, + auth_proto, auth_data); + if (screen != NULL) + fprintf(f, "add %.*s/unix%s %s %s\n", + (int)(screen-display), display, + screen, auth_proto, auth_data); pclose(f); - } else - fprintf(stderr, "Could not run %s -q -\n", XAUTH_PATH); + } else { + fprintf(stderr, "Could not run %s\n", + cmd); + } } } -#endif /* XAUTH_PATH */ - /* Get the last component of the shell name. */ cp = strrchr(shell, '/'); if (cp) @@ -988,7 +1102,8 @@ struct stat mailstat; mailbox = getenv("MAIL"); if (mailbox != NULL) { - if (stat(mailbox, &mailstat) != 0 || mailstat.st_size == 0) + if (stat(mailbox, &mailstat) != 0 || + mailstat.st_size == 0) printf("No mail.\n"); else if (mailstat.st_mtime < mailstat.st_atime) printf("You have mail.\n"); @@ -1013,8 +1128,8 @@ } else { /* Launch login(1). */ - execl("/usr/bin/login", "login", "-h", get_remote_ipaddr(), - "-p", "-f", "--", pw->pw_name, NULL); + execl("/usr/bin/login", "login", "-h", hostname, + "-p", "-f", "--", pw->pw_name, NULL); /* Login couldn't be executed, die. */ @@ -1097,7 +1212,7 @@ } s->pw = auth_get_user(); if (s->pw == NULL) - fatal("no user for session %i", s->self); + fatal("no user for session %d", s->self); debug("session_open: session %d: link with channel %d", s->self, chanid); s->chanid = chanid; return 1; @@ -1149,9 +1264,11 @@ int session_pty_req(Session *s) { - unsigned int len; + u_int len; char *term_modes; /* encoded terminal modes */ + if (no_pty_flag) + return 0; if (s->ttyfd != -1) return 0; s->term = packet_get_string(&len); @@ -1196,13 +1313,25 @@ int session_subsystem_req(Session *s) { - unsigned int len; + u_int len; int success = 0; char *subsys = packet_get_string(&len); + int i; packet_done(); log("subsystem request for %s", subsys); + for (i = 0; i < options.num_subsystems; i++) { + if(strcmp(subsys, options.subsystem_name[i]) == 0) { + debug("subsystem: exec() %s", options.subsystem_command[i]); + do_exec_no_pty(s, options.subsystem_command[i], s->pw); + success = 1; + } + } + + if (!success) + log("subsystem request for %s failed, subsystem not found", subsys); + xfree(subsys); return success; } @@ -1210,6 +1339,11 @@ 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; @@ -1250,16 +1384,70 @@ return 0; } strlcat(xauthfile, "/cookies", MAXPATHLEN); - open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600); + 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; } +int +session_shell_req(Session *s) +{ + /* if forced_command == NULL, the shell is execed */ + char *shell = forced_command; + packet_done(); + s->extended = 1; + if (s->ttyfd == -1) + do_exec_no_pty(s, shell, s->pw); + else + do_exec_pty(s, shell, s->pw); + return 1; +} + +int +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); + } + s->extended = 1; + if (s->ttyfd == -1) + do_exec_no_pty(s, command, s->pw); + else + do_exec_pty(s, command, s->pw); + if (forced_command == NULL) + xfree(command); + return 1; +} + +int +session_auth_agent_req(Session *s) +{ + static int called = 0; + packet_done(); + if (no_agent_forwarding_flag) { + debug("session_auth_agent_req: no_agent_forwarding_flag"); + return 0; + } + if (called) { + return 0; + } else { + called = 1; + return auth_input_request_forwarding(s->pw); + } +} + void session_input_channel_req(int id, void *arg) { - unsigned int len; + u_int len; int reply; int success = 0; char *rtype; @@ -1285,27 +1473,15 @@ */ if (c->type == SSH_CHANNEL_LARVAL) { if (strcmp(rtype, "shell") == 0) { - packet_done(); - s->extended = 1; - if (s->ttyfd == -1) - do_exec_no_pty(s, NULL, s->pw); - else - do_exec_pty(s, NULL, s->pw); - success = 1; + success = session_shell_req(s); } else if (strcmp(rtype, "exec") == 0) { - char *command = packet_get_string(&len); - packet_done(); - s->extended = 1; - if (s->ttyfd == -1) - do_exec_no_pty(s, command, s->pw); - else - do_exec_pty(s, command, s->pw); - xfree(command); - success = 1; + success = session_exec_req(s); } else if (strcmp(rtype, "pty-req") == 0) { success = session_pty_req(s); } else if (strcmp(rtype, "x11-req") == 0) { success = session_x11_req(s); + } else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) { + success = session_auth_agent_req(s); } else if (strcmp(rtype, "subsystem") == 0) { success = session_subsystem_req(s); } @@ -1336,7 +1512,8 @@ fatal("no channel for session %d", s->self); channel_set_fds(s->chanid, fdout, fdin, fderr, - fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ); + fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, + 1); } void @@ -1345,7 +1522,7 @@ if (s == NULL || s->ttyfd == -1) return; - debug("session_pty_cleanup: session %i release %s", s->self, s->tty); + debug("session_pty_cleanup: session %d release %s", s->self, s->tty); /* Cancel the cleanup function. */ fatal_remove_cleanup(pty_cleanup_proc, (void *)s); @@ -1503,13 +1680,23 @@ } void -do_authenticated2(void) +do_authenticated2(Authctxt *authctxt) { /* * Cancel the alarm we set to limit the time taken for * authentication. */ alarm(0); + if (startup_pipe != -1) { + close(startup_pipe); + startup_pipe = -1; + } +#ifdef HAVE_LOGIN_CAP + if ((lc = login_getclass(authctxt->pw->pw_class)) == NULL) { + error("unable to get login class"); + return; + } +#endif server_loop2(); if (xauthfile) xauthfile_cleanup_proc(NULL);