X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/bcbf86ecce0d10003d08a40b67f2db96702c132a..e5d7a405cf2643442c0462107988377736f59efc:/session.c diff --git a/session.c b/session.c index 0cc919c6..800f2112 100644 --- a/session.c +++ b/session.c @@ -9,7 +9,7 @@ * called by a name other than "ssh" or "Secure Shell". * * SSH2 support by Markus Friedl. - * Copyright (c) 2000 Markus Friedl. All rights reserved. + * 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 @@ -33,39 +33,45 @@ */ #include "includes.h" -RCSID("$OpenBSD: session.c,v 1.37 2000/09/07 20:27:53 deraadt Exp $"); +RCSID("$OpenBSD: session.c,v 1.64 2001/03/20 19:35:29 markus Exp $"); -#include "xmalloc.h" #include "ssh.h" -#include "pty.h" +#include "ssh1.h" +#include "ssh2.h" +#include "xmalloc.h" +#include "sshpty.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 "sshlogin.h" +#include "serverloop.h" +#include "canohost.h" +#include "session.h" #ifdef WITH_IRIX_PROJECT #include #endif /* WITH_IRIX_PROJECT */ +#ifdef WITH_IRIX_JOBS +#include +#endif +#ifdef WITH_IRIX_AUDIT +#include +#endif /* WITH_IRIX_AUDIT */ #if defined(HAVE_USERSEC_H) #include #endif -#ifdef HAVE_OSF_SIA -# include -# include -#endif - #ifdef HAVE_CYGWIN #include #include @@ -83,8 +89,8 @@ RCSID("$OpenBSD: session.c,v 1.37 2000/09/07 20:27:53 deraadt Exp $"); # define S_UNOFILE_HARD S_UNOFILE "_hard" #endif -#ifdef HAVE_LOGIN_CAP -#include +#ifdef _AIX +# include #endif /* types */ @@ -94,7 +100,6 @@ typedef struct Session Session; struct Session { int used; int self; - int extended; struct passwd *pw; pid_t pid; /* tty */ @@ -110,6 +115,7 @@ struct Session { int single_connection; /* proto 2 */ int chanid; + int is_subsystem; }; /* func */ @@ -118,26 +124,17 @@ Session *session_new(void); void session_set_fds(Session *s, int fdin, int fdout, int fderr); void session_pty_cleanup(Session *s); 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); - -void -do_child(const char *command, struct passwd * pw, const char *term, - const char *display, const char *auth_proto, - const char *auth_data, const char *ttyname); +void do_exec_pty(Session *s, const char *command); +void do_exec_no_pty(Session *s, const char *command); +void do_login(Session *s, const char *command); +void do_child(Session *s, const char *command); /* import */ extern ServerOptions options; -#ifdef HAVE___PROGNAME extern char *__progname; -#else /* HAVE___PROGNAME */ -static const char *__progname = "sshd"; -#endif /* HAVE___PROGNAME */ - extern int log_stderr; extern int debug_flag; -extern unsigned int utmp_len; +extern u_int utmp_len; extern int startup_pipe; @@ -145,11 +142,12 @@ extern int startup_pipe; static char *xauthfile; /* original command from peer. */ -char *original_command = NULL; +char *original_command = NULL; /* data */ #define MAX_SESSIONS 10 Session sessions[MAX_SESSIONS]; + #ifdef WITH_AIXAUTHENTICATE /* AIX's lastlogin message, set in auth1.c */ char *aixloginmsg; @@ -217,7 +215,8 @@ do_authenticated(struct passwd * pw) char *command; int n_bytes; int plen; - unsigned int proto_len, data_len, dlen; + u_int proto_len, data_len, dlen; + int screen_flag; /* * Cancel the alarm we set to limit the time taken for @@ -229,20 +228,13 @@ do_authenticated(struct passwd * pw) startup_pipe = -1; } - /* - * Inform the channel mechanism that we are the server side and that - * the client may request to connect to any port at all. (The user - * could do it anyway, and we wouldn\'t know what is permitted except - * 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 defined(HAVE_LOGIN_CAP) && defined(HAVE_PW_CLASS_IN_PASSWD) if ((lc = login_getclass(pw->pw_class)) == NULL) { error("unable to get login class"); return; @@ -341,12 +333,23 @@ do_authenticated(struct passwd * pw) 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) + screen_flag = packet_get_protocol_flags() & + SSH_PROTOFLAG_SCREEN_NUMBER; + debug2("SSH_PROTOFLAG_SCREEN_NUMBER: %d", screen_flag); + + if (packet_remaining() == 4) { + 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 + } 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) @@ -388,6 +391,10 @@ do_authenticated(struct passwd * pw) 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; @@ -400,10 +407,6 @@ do_authenticated(struct passwd * pw) 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); @@ -418,9 +421,9 @@ do_authenticated(struct passwd * pw) debug("Forced command '%.500s'", forced_command); } if (have_pty) - do_exec_pty(s, command, pw); + do_exec_pty(s, command); else - do_exec_no_pty(s, command, pw); + do_exec_no_pty(s, command); if (command != NULL) xfree(command); @@ -454,7 +457,7 @@ do_authenticated(struct passwd * pw) * setting up file descriptors and such. */ void -do_exec_no_pty(Session *s, const char *command, struct passwd * pw) +do_exec_no_pty(Session *s, const char *command) { int pid; @@ -477,8 +480,8 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw) session_proctitle(s); -#ifdef USE_PAM - do_pam_setcred(); +#if defined(USE_PAM) + do_pam_setcred(); #endif /* USE_PAM */ /* Fork the child. */ @@ -486,6 +489,8 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw) /* 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. @@ -531,7 +536,7 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw) #endif /* USE_PIPES */ /* Do processing for the child (exec command etc). */ - do_child(command, pw, NULL, s->display, s->auth_proto, s->auth_data, NULL); + do_child(s, command); /* NOTREACHED */ } #ifdef HAVE_CYGWIN @@ -541,6 +546,8 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw) 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]); @@ -548,11 +555,11 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw) close(perr[1]); if (compat20) { - session_set_fds(s, pin[1], pout[0], s->extended ? perr[0] : -1); + session_set_fds(s, pin[1], pout[0], s->is_subsystem ? -1 : perr[0]); } else { /* Enter the interactive session. */ server_loop(pid, pin[1], pout[0], perr[0]); - /* server_loop has closed pin[1], pout[1], and perr[1]. */ + /* server_loop has closed pin[1], pout[0], and perr[0]. */ } #else /* USE_PIPES */ /* We are the parent. Close the child sides of the socket pairs. */ @@ -564,7 +571,7 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw) * handle the case that fdin and fdout are the same. */ if (compat20) { - session_set_fds(s, inout[1], inout[1], s->extended ? err[1] : -1); + session_set_fds(s, inout[1], inout[1], s->is_subsystem ? -1 : err[1]); } else { server_loop(pid, inout[1], inout[1], err[1]); /* server_loop has closed inout[1] and err[1]. */ @@ -579,7 +586,7 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw) * lastlog, and other such operations. */ void -do_exec_pty(Session *s, const char *command, struct passwd * pw) +do_exec_pty(Session *s, const char *command) { int fdout, ptyfd, ttyfd, ptymaster; pid_t pid; @@ -589,16 +596,18 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw) ptyfd = s->ptyfd; ttyfd = s->ttyfd; -#ifdef USE_PAM - do_pam_session(pw->pw_name, s->tty); - do_pam_setcred(); -#endif /* USE_PAM */ +#if defined(USE_PAM) + do_pam_session(pw->pw_name, s->tty); + do_pam_setcred(); +#endif /* Fork the child. */ if ((pid = fork()) == 0) { /* 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); @@ -621,12 +630,11 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw) close(ttyfd); /* record login, etc. similar to login(1) */ - if (command == NULL && !options.use_login) - do_login(s); + if (!(options.use_login && command == NULL)) + do_login(s, command); /* 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(s, command); /* NOTREACHED */ } #ifdef HAVE_CYGWIN @@ -656,6 +664,7 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw) s->ptymaster = ptymaster; /* Enter interactive session. */ + packet_set_interactive(1); if (compat20) { session_set_fds(s, ptyfd, fdout, -1); } else { @@ -670,7 +679,7 @@ get_remote_name_or_ip(void) { static const char *remote = ""; if (utmp_len > 0) - remote = get_canonical_hostname(); + remote = get_canonical_hostname(options.reverse_mapping_check); if (utmp_len == 0 || strlen(remote) > utmp_len) remote = get_remote_ipaddr(); return remote; @@ -678,7 +687,7 @@ get_remote_name_or_ip(void) /* administrative, login(1)-like work */ void -do_login(Session *s) +do_login(Session *s, const char *command) { FILE *f; char *time_string; @@ -705,10 +714,6 @@ do_login(Session *s) } } - /* Get the time and hostname when the user last logged in. */ - last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name, - hostname, sizeof(hostname)); - /* 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, @@ -718,7 +723,20 @@ do_login(Session *s) record_login(pid, s->tty, pw->pw_name, pw->pw_uid, get_remote_name_or_ip(), (struct sockaddr *)&from); - /* Done if .hushlogin exists. */ +#ifdef USE_PAM + /* + * If password change is needed, do it now. + * This needs to occur before the ~/.hushlogin check. + */ + if (is_pam_password_change_required()) { + print_pam_messages(); + do_pam_chauthtok(); + } +#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) @@ -728,7 +746,8 @@ do_login(Session *s) return; #ifdef USE_PAM - print_pam_messages(); + if (!is_pam_password_change_required()) + print_pam_messages(); #endif /* USE_PAM */ #ifdef WITH_AIXAUTHENTICATE if (aixloginmsg && *aixloginmsg) @@ -739,7 +758,7 @@ do_login(Session *s) time_string = ctime(&last_login_time); if (strchr(time_string, '\n')) *strchr(time_string, '\n') = 0; - if (strcmp(buf, "") == 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); @@ -764,10 +783,10 @@ do_login(Session *s) * 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; /* @@ -805,7 +824,7 @@ child_set_env(char ***envp, unsigned int *envsizep, const char *name, * 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; @@ -851,11 +870,11 @@ void do_pam_environment(char ***env, int *envsize) if ((pam_env = fetch_pam_environment()) == NULL) return; - + for(i = 0; pam_env[i] != NULL; i++) { if ((equals = strstr(pam_env[i], "=")) == NULL) continue; - + if (strlen(pam_env[i]) < (sizeof(var_name) - 1)) { memset(var_name, '\0', sizeof(var_name)); memset(var_val, '\0', sizeof(var_val)); @@ -863,7 +882,7 @@ void do_pam_environment(char ***env, int *envsize) strncpy(var_name, pam_env[i], equals - pam_env[i]); strcpy(var_val, equals + 1); - debug("PAM environment: %s=%s", var_name, var_val); + debug3("PAM environment: %s=%s", var_name, var_val); child_set_env(env, envsize, var_name, var_val); } @@ -871,6 +890,31 @@ void do_pam_environment(char ***env, int *envsize) } #endif /* USE_PAM */ +#ifdef HAVE_CYGWIN +void copy_environment(char ***env, 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); + + child_set_env(env, envsize, var_name, var_val); + } + } +} +#endif + #if defined(HAVE_GETUSERATTR) /* * AIX-specific login initialisation @@ -956,22 +1000,29 @@ void set_limits_from_userattr(char *user) * ids, and executing the command or shell. */ void -do_child(const char *command, struct passwd * pw, const char *term, - const char *display, const char *auth_proto, - const char *auth_data, const char *ttyname) +do_child(Session *s, const char *command) { const char *shell, *hostname = NULL, *cp = NULL; + struct passwd * pw = s->pw; char buf[256]; char cmd[1024]; FILE *f = NULL; - unsigned int envsize, i; + u_int envsize, i; char **env; extern char **environ; struct stat st; char *argv[10]; + int do_xauth = s->auth_proto != NULL && s->auth_data != NULL; #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 */ /* login(1) is only called if we execute the login shell */ if (options.use_login && command != NULL) @@ -1002,20 +1053,7 @@ do_child(const char *command, struct passwd * pw, const char *term, switch, so we let login(1) to this for us. */ if (!options.use_login) { #ifdef HAVE_OSF_SIA - extern char **saved_argv; - extern int saved_argc; - char *host = get_canonical_hostname (); - - if (sia_become_user(NULL, saved_argc, saved_argv, host, - pw->pw_name, ttyname, 0, NULL, NULL, SIA_BEU_SETLUID) != - SIASUCCESS) { - perror("sia_become_user"); - exit(1); - } - if (setreuid(geteuid(), geteuid()) < 0) { - perror("setreuid"); - exit(1); - } + session_setup_sia(pw->pw_name, s->ttyfd == -1 ? NULL : s->tty); #else /* HAVE_OSF_SIA */ #ifdef HAVE_CYGWIN if (is_winnt) { @@ -1031,7 +1069,20 @@ do_child(const char *command, struct passwd * pw, const char *term, 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 */ + 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) { @@ -1044,11 +1095,20 @@ do_child(const char *command, struct passwd * pw, const char *term, exit(1); } endgrent(); +# 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 (newarraysess() != 0) - fatal("Failed to set up new array session: %.100s", - strerror(errno)); + 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 */ @@ -1060,6 +1120,33 @@ do_child(const char *command, struct passwd * pw, const char *term, 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->pw_uid); # endif /* HAVE_LOGIN_CAP */ @@ -1103,15 +1190,7 @@ do_child(const char *command, struct passwd * pw, const char *term, * The Windows environment contains some setting which are * important for a running system. They must not be dropped. */ - { - char **ep; - for (ep = environ; *ep; ++ep) { - char *esp = strchr(*ep, '='); - *esp = '\0'; - child_set_env(&env, &envsize, *ep, esp + 1); - *esp = '='; - } - } + copy_environment(&env, &envsize); #endif if (!options.use_login) { @@ -1122,8 +1201,8 @@ do_child(const char *command, struct passwd * pw, const char *term, #ifdef HAVE_LOGIN_CAP (void) setusercontext(lc, pw, pw->pw_uid, LOGIN_SETPATH); child_set_env(&env, &envsize, "PATH", getenv("PATH")); -#else -#ifndef HAVE_CYGWIN +#else /* HAVE_LOGIN_CAP */ +# ifndef HAVE_CYGWIN /* * There's no standard path on Windows. The path contains * important components pointing to the system directories, @@ -1131,8 +1210,8 @@ do_child(const char *command, struct passwd * pw, const char *term, * remains intact here. */ child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); -#endif -#endif +# endif /* HAVE_CYGWIN */ +#endif /* HAVE_LOGIN_CAP */ snprintf(buf, sizeof buf, "%.200s/%.50s", _PATH_MAILDIR, pw->pw_name); @@ -1163,26 +1242,22 @@ do_child(const char *command, struct passwd * pw, const char *term, get_remote_ipaddr(), get_remote_port(), get_local_port()); child_set_env(&env, &envsize, "SSH_CLIENT", buf); - if (ttyname) - child_set_env(&env, &envsize, "SSH_TTY", ttyname); - if (term) - child_set_env(&env, &envsize, "TERM", term); - if (display) - child_set_env(&env, &envsize, "DISPLAY", display); + if (s->ttyfd != -1) + child_set_env(&env, &envsize, "SSH_TTY", s->tty); + if (s->term) + child_set_env(&env, &envsize, "TERM", s->term); + if (s->display) + child_set_env(&env, &envsize, "DISPLAY", s->display); if (original_command) child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND", original_command); #ifdef _AIX - { - char *authstate,*krb5cc; - - if ((authstate = getenv("AUTHSTATE")) != NULL) - child_set_env(&env,&envsize,"AUTHSTATE",authstate); - - if ((krb5cc = getenv("KRB5CCNAME")) != NULL) - child_set_env(&env,&envsize,"KRB5CCNAME",krb5cc); - } + 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 @@ -1199,8 +1274,6 @@ do_child(const char *command, struct passwd * pw, const char *term, do_pam_environment(&env, &envsize); #endif /* USE_PAM */ - read_environment_file(&env,&envsize,"/etc/environment"); - if (xauthfile) child_set_env(&env, &envsize, "XAUTHORITY", xauthfile); if (auth_get_socket_name() != NULL) @@ -1278,62 +1351,66 @@ do_child(const char *command, struct passwd * pw, const char *term, * 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 "_PATH_BSHELL" %s\n", SSH_USER_RC); - - f = popen(_PATH_BSHELL " " SSH_USER_RC, "w"); + fprintf(stderr, "Running %s %s\n", _PATH_BSHELL, + _PATH_SSH_USER_RC); + 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); + if (do_xauth) + fprintf(f, "%s %s\n", s->auth_proto, + s->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 "_PATH_BSHELL" %s\n", SSH_SYSTEM_RC); + fprintf(stderr, "Running %s %s\n", _PATH_BSHELL, + _PATH_SSH_SYSTEM_RC); - f = popen(_PATH_BSHELL " " 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); + if (do_xauth) + fprintf(f, "%s %s\n", s->auth_proto, + s->auth_data); pclose(f); } else - fprintf(stderr, "Could not run %s\n", SSH_SYSTEM_RC); - } else if (options.xauth_location != NULL) { + 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 (auth_proto != NULL && auth_data != NULL) { - char *screen = strchr(display, ':'); - if (debug_flag) { + char *screen = strchr(s->display, ':'); + + if (debug_flag) { + fprintf(stderr, + "Running %.100s add " + "%.100s %.100s %.100s\n", + options.xauth_location, s->display, + s->auth_proto, s->auth_data); + if (screen != NULL) fprintf(stderr, - "Running %.100s add %.100s %.100s %.100s\n", - options.xauth_location, display, - auth_proto, auth_data); -#ifndef HAVE_CYGWIN - if (screen != NULL) - fprintf(stderr, - "Adding %.*s/unix%s %s %s\n", - (int)(screen-display), display, - screen, auth_proto, auth_data); -#endif - } - 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); -#ifndef HAVE_CYGWIN - if (screen != NULL) - fprintf(f, "add %.*s/unix%s %s %s\n", - (int)(screen-display), display, - screen, auth_proto, auth_data); -#endif - pclose(f); - } else { - fprintf(stderr, "Could not run %s\n", - cmd); - } + "Adding %.*s/unix%s %s %s\n", + (int)(screen - s->display), + s->display, screen, + 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->display, + s->auth_proto, s->auth_data); + if (screen != NULL) + fprintf(f, "add %.*s/unix%s %s %s\n", + (int)(screen - s->display), + s->display, screen, + 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. */ @@ -1356,9 +1433,10 @@ do_child(const char *command, struct passwd * pw, const char *term, * Check for mail if we have a tty and it was enabled * in server options. */ - if (ttyname && options.check_mail) { + if (s->ttyfd != -1 && options.check_mail) { char *mailbox; struct stat mailstat; + mailbox = getenv("MAIL"); if (mailbox != NULL) { if (stat(mailbox, &mailstat) != 0 || @@ -1426,7 +1504,7 @@ session_new(void) Session *s = &sessions[i]; if (! s->used) { s->pid = 0; - s->extended = 0; + s->is_subsystem = 0; s->chanid = -1; s->ptyfd = -1; s->ttyfd = -1; @@ -1471,7 +1549,7 @@ session_open(int chanid) } 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; @@ -1523,7 +1601,7 @@ session_window_change_req(Session *s) int session_pty_req(Session *s) { - unsigned int len; + u_int len; char *term_modes; /* encoded terminal modes */ if (no_pty_flag) @@ -1572,7 +1650,7 @@ session_pty_req(Session *s) int session_subsystem_req(Session *s) { - unsigned int len; + u_int len; int success = 0; char *subsys = packet_get_string(&len); int i; @@ -1583,7 +1661,8 @@ session_subsystem_req(Session *s) 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); + s->is_subsystem = 1; + do_exec_no_pty(s, options.subsystem_command[i]); success = 1; } } @@ -1657,18 +1736,17 @@ 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); + do_exec_no_pty(s, shell); else - do_exec_pty(s, shell, s->pw); + do_exec_pty(s, shell); return 1; } int session_exec_req(Session *s) { - unsigned int len; + u_int len; char *command = packet_get_string(&len); packet_done(); if (forced_command) { @@ -1676,20 +1754,36 @@ session_exec_req(Session *s) command = forced_command; debug("Forced command '%.500s'", forced_command); } - s->extended = 1; if (s->ttyfd == -1) - do_exec_no_pty(s, command, s->pw); + do_exec_no_pty(s, command); else - do_exec_pty(s, command, s->pw); + do_exec_pty(s, command); 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; @@ -1710,8 +1804,8 @@ session_input_channel_req(int id, void *arg) s->self, id, rtype, reply); /* - * a session is in LARVAL state until a shell - * or programm is executed + * a session is in LARVAL state until a shell, a command + * or a subsystem is executed */ if (c->type == SSH_CHANNEL_LARVAL) { if (strcmp(rtype, "shell") == 0) { @@ -1722,6 +1816,8 @@ session_input_channel_req(int id, void *arg) 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); } @@ -1752,7 +1848,8 @@ session_set_fds(Session *s, int fdin, int fdout, int fderr) 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 @@ -1761,7 +1858,7 @@ session_pty_cleanup(Session *s) 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); @@ -1888,8 +1985,6 @@ session_close_by_channel(int id, void *arg) session_close(s); } else { /* notify child, delay session cleanup */ - if (s->pid <= 1) - fatal("session_close_by_channel: Unsafe s->pid = %d", s->pid); if (kill(s->pid, (s->ttyfd == -1) ? SIGTERM : SIGHUP) < 0) error("session_close_by_channel: kill %d: %s", s->pid, strerror(errno)); @@ -1925,12 +2020,8 @@ session_proctitle(Session *s) } void -do_authenticated2(void) +do_authenticated2(Authctxt *authctxt) { -#ifdef HAVE_LOGIN_CAP - struct passwd *pw; -#endif - /* * Cancel the alarm we set to limit the time taken for * authentication. @@ -1940,9 +2031,10 @@ do_authenticated2(void) close(startup_pipe); startup_pipe = -1; } -#ifdef HAVE_LOGIN_CAP - pw = auth_get_user(); - if ((lc = login_getclass(pw->pw_class)) == NULL) { + if (!no_port_forwarding_flag && options.allow_tcp_forwarding) + channel_permit_all_opens(); +#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; }