]> andersk Git - openssh.git/blobdiff - session.c
- djm@cvs.openbsd.org 2010/01/30 02:54:53
[openssh.git] / session.c
index c8ed25234739d8c98b3cb7973df5988a129e3ea0..fd7acbe03bb1751b89748da23b2d342bd6925c1a 100644 (file)
--- a/session.c
+++ b/session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.237 2008/05/08 12:21:16 djm Exp $ */
+/* $OpenBSD: session.c,v 1.251 2010/01/12 08:33:17 dtucker Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
 #include <kafs.h>
 #endif
 
+#define IS_INTERNAL_SFTP(c) \
+       (!strncmp(c, INTERNAL_SFTP_NAME, sizeof(INTERNAL_SFTP_NAME) - 1) && \
+        (c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\0' || \
+         c[sizeof(INTERNAL_SFTP_NAME) - 1] == ' ' || \
+         c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\t'))
+
 /* func */
 
 Session *session_new(void);
-void   session_set_fds(Session *, int, int, int);
+void   session_set_fds(Session *, int, int, int, int);
 void   session_pty_cleanup(Session *);
 void   session_proctitle(Session *);
 int    session_setup_x11fwd(Session *);
@@ -136,9 +142,10 @@ static int sessions_first_unused = -1;
 static int sessions_nalloc = 0;
 static Session *sessions = NULL;
 
-#define SUBSYSTEM_NONE         0
-#define SUBSYSTEM_EXT          1
-#define SUBSYSTEM_INT_SFTP     2
+#define SUBSYSTEM_NONE                 0
+#define SUBSYSTEM_EXT                  1
+#define SUBSYSTEM_INT_SFTP             2
+#define SUBSYSTEM_INT_SFTP_ERROR       3
 
 #ifdef HAVE_LOGIN_CAP
 login_cap_t *lc;
@@ -228,7 +235,7 @@ auth_input_request_forwarding(struct passwd * pw)
            SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,
            CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
            0, "auth socket", 1);
-       strlcpy(nc->path, auth_sock_name, sizeof(nc->path));
+       nc->path = xstrdup(auth_sock_name);
        return 1;
 
  authsock_err:
@@ -565,8 +572,7 @@ do_exec_no_pty(Session *s, const char *command)
        signal(WJSIGNAL, cray_job_termination_handler);
 #endif /* _UNICOS */
 #ifdef HAVE_CYGWIN
-       if (is_winnt)
-               cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
+       cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
 #endif
 
        s->pid = pid;
@@ -591,7 +597,7 @@ do_exec_no_pty(Session *s, const char *command)
                        close(perr[0]);
                        perr[0] = -1;
                }
-               session_set_fds(s, pin[1], pout[0], perr[0]);
+               session_set_fds(s, pin[1], pout[0], perr[0], 0);
        } else {
                /* Enter the interactive session. */
                server_loop(pid, pin[1], pout[0], perr[0]);
@@ -608,7 +614,7 @@ do_exec_no_pty(Session *s, const char *command)
         */
        if (compat20) {
                session_set_fds(s, inout[1], inout[1],
-                   s->is_subsystem ? -1 : err[1]);
+                   s->is_subsystem ? -1 : err[1], 0);
                if (s->is_subsystem)
                        close(err[1]);
        } else {
@@ -710,8 +716,8 @@ do_exec_pty(Session *s, const char *command)
                 * Do common processing for the child, such as execing
                 * the command.
                 */
-               do_child(s, command);
-               /* NOTREACHED */
+               do_child(s, command);
+               /* NOTREACHED */
        default:
                break;
        }
@@ -720,8 +726,7 @@ do_exec_pty(Session *s, const char *command)
        signal(WJSIGNAL, cray_job_termination_handler);
 #endif /* _UNICOS */
 #ifdef HAVE_CYGWIN
-       if (is_winnt)
-               cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
+       cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
 #endif
 
        s->pid = pid;
@@ -733,7 +738,7 @@ do_exec_pty(Session *s, const char *command)
        s->ptymaster = ptymaster;
        packet_set_interactive(1);
        if (compat20) {
-               session_set_fds(s, ptyfd, fdout, -1);
+               session_set_fds(s, ptyfd, fdout, -1, 1);
        } else {
                server_loop(pid, ptyfd, fdout, -1);
                /* server_loop _has_ closed ptyfd and fdout. */
@@ -781,17 +786,19 @@ do_exec(Session *s, const char *command)
        if (options.adm_forced_command) {
                original_command = command;
                command = options.adm_forced_command;
-               if (strcmp(INTERNAL_SFTP_NAME, command) == 0)
-                       s->is_subsystem = SUBSYSTEM_INT_SFTP;
-               else if (s->is_subsystem)
+               if (IS_INTERNAL_SFTP(command)) {
+                       s->is_subsystem = s->is_subsystem ?
+                           SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR;
+               } else if (s->is_subsystem)
                        s->is_subsystem = SUBSYSTEM_EXT;
                debug("Forced command (config) '%.900s'", command);
        } else if (forced_command) {
                original_command = command;
                command = forced_command;
-               if (strcmp(INTERNAL_SFTP_NAME, command) == 0)
-                       s->is_subsystem = SUBSYSTEM_INT_SFTP;
-               else if (s->is_subsystem)
+               if (IS_INTERNAL_SFTP(command)) {
+                       s->is_subsystem = s->is_subsystem ?
+                           SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR;
+               } else if (s->is_subsystem)
                        s->is_subsystem = SUBSYSTEM_EXT;
                debug("Forced command (key option) '%.900s'", command);
        }
@@ -841,7 +848,7 @@ do_login(Session *s, const char *command)
        fromlen = sizeof(from);
        if (packet_connection_is_on_socket()) {
                if (getpeername(packet_get_connection_in(),
-                   (struct sockaddr *) & from, &fromlen) < 0) {
+                   (struct sockaddr *)&from, &fromlen) < 0) {
                        debug("getpeername: %.100s", strerror(errno));
                        cleanup_exit(255);
                }
@@ -926,7 +933,7 @@ check_quietlogin(Session *s, const char *command)
 
 /*
  * Sets the value of the given variable in the environment.  If the variable
- * already exists, its value is overriden.
+ * already exists, its value is overridden.
  */
 void
 child_set_env(char ***envp, u_int *envsizep, const char *name,
@@ -1110,7 +1117,7 @@ do_setup_env(Session *s, const char *shell)
        u_int i, envsize;
        char **env, *laddr;
        struct passwd *pw = s->pw;
-#ifndef HAVE_LOGIN_CAP
+#if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN)
        char *path = NULL;
 #endif
 
@@ -1370,26 +1377,32 @@ static void
 do_nologin(struct passwd *pw)
 {
        FILE *f = NULL;
-       char buf[1024];
+       char buf[1024], *nl, *def_nl = _PATH_NOLOGIN;
+       struct stat sb;
 
 #ifdef HAVE_LOGIN_CAP
-       if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid)
-               f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN,
-                   _PATH_NOLOGIN), "r");
+       if (login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid)
+               return;
+       nl = login_getcapstr(lc, "nologin", def_nl, def_nl);
 #else
-       if (pw->pw_uid)
-               f = fopen(_PATH_NOLOGIN, "r");
+       if (pw->pw_uid == 0)
+               return;
+       nl = def_nl;
 #endif
-       if (f) {
-               /* /etc/nologin exists.  Print its contents and exit. */
-               logit("User %.100s not allowed because %s exists",
-                   pw->pw_name, _PATH_NOLOGIN);
-               while (fgets(buf, sizeof(buf), f))
-                       fputs(buf, stderr);
-               fclose(f);
-               fflush(NULL);
-               exit(254);
+       if (stat(nl, &sb) == -1) {
+               if (nl != def_nl)
+                       xfree(nl);
+               return;
        }
+
+       /* /etc/nologin exists.  Print its contents if we can and exit. */
+       logit("User %.100s not allowed because %s exists", pw->pw_name, nl);
+       if ((f = fopen(nl, "r")) != NULL) {
+               while (fgets(buf, sizeof(buf), f))
+                       fputs(buf, stderr);
+               fclose(f);
+       }
+       exit(254);
 }
 
 /*
@@ -1462,11 +1475,6 @@ do_setusercontext(struct passwd *pw)
        if (getuid() == 0 || geteuid() == 0)
 #endif /* HAVE_CYGWIN */
        {
-
-#ifdef HAVE_SETPCRED
-               if (setpcred(pw->pw_name, (char **)NULL) == -1)
-                       fatal("Failed to set process credentials");
-#endif /* HAVE_SETPCRED */
 #ifdef HAVE_LOGIN_CAP
 # ifdef __bsdi__
                setpgid(0, 0);
@@ -1534,6 +1542,10 @@ do_setusercontext(struct passwd *pw)
                        free(chroot_path);
                }
 
+#ifdef HAVE_SETPCRED
+               if (setpcred(pw->pw_name, (char **)NULL) == -1)
+                       fatal("Failed to set process credentials");
+#endif /* HAVE_SETPCRED */
 #ifdef HAVE_LOGIN_CAP
                if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUSER) < 0) {
                        perror("unable to set user context (setuser)");
@@ -1545,9 +1557,6 @@ do_setusercontext(struct passwd *pw)
 #endif
        }
 
-#ifdef HAVE_CYGWIN
-       if (is_winnt)
-#endif
        if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
                fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
 
@@ -1647,6 +1656,7 @@ do_child(Session *s, const char *command)
        char *argv[ARGV_MAX];
        const char *shell, *shell0, *hostname = NULL;
        struct passwd *pw = s->pw;
+       int r = 0;
 
        /* remove hostkey from the child's memory */
        destroy_sensitive_data();
@@ -1762,12 +1772,16 @@ do_child(Session *s, const char *command)
 
        /* Change current directory to the user's home directory. */
        if (chdir(pw->pw_dir) < 0) {
-               fprintf(stderr, "Could not chdir to home directory %s: %s\n",
-                   pw->pw_dir, strerror(errno));
+               /* Suppress missing homedir warning for chroot case */
 #ifdef HAVE_LOGIN_CAP
-               if (login_getcapbool(lc, "requirehome", 0))
-                       exit(1);
+               r = login_getcapbool(lc, "requirehome", 0);
 #endif
+               if (r || options.chroot_directory == NULL)
+                       fprintf(stderr, "Could not chdir to home "
+                           "directory %s: %s\n", pw->pw_dir,
+                           strerror(errno));
+               if (r)
+                       exit(1);
        }
 
        closefrom(STDERR_FILENO + 1);
@@ -1778,22 +1792,31 @@ do_child(Session *s, const char *command)
        /* restore SIGPIPE for child */
        signal(SIGPIPE, SIG_DFL);
 
-       if (s->is_subsystem == SUBSYSTEM_INT_SFTP) {
+       if (s->is_subsystem == SUBSYSTEM_INT_SFTP_ERROR) {
+               printf("This service allows sftp connections only.\n");
+               fflush(NULL);
+               exit(1);
+       } else if (s->is_subsystem == SUBSYSTEM_INT_SFTP) {
                extern int optind, optreset;
                int i;
                char *p, *args;
 
-               setproctitle("%s@internal-sftp-server", s->pw->pw_name);
-               args = strdup(command ? command : "sftp-server");
+               setproctitle("%s@%s", s->pw->pw_name, INTERNAL_SFTP_NAME);
+               args = xstrdup(command ? command : "sftp-server");
                for (i = 0, (p = strtok(args, " ")); p; (p = strtok(NULL, " ")))
                        if (i < ARGV_MAX - 1)
                                argv[i++] = p;
                argv[i] = NULL;
                optind = optreset = 1;
                __progname = argv[0];
+#ifdef WITH_SELINUX
+               ssh_selinux_change_context("sftpd_t");
+#endif
                exit(sftp_server_main(i, argv, s->pw));
        }
 
+       fflush(NULL);
+
        if (options.use_login) {
                launch_login(pw, hostname);
                /* NEVERREACHED */
@@ -2104,16 +2127,16 @@ session_subsystem_req(Session *s)
                if (strcmp(subsys, options.subsystem_name[i]) == 0) {
                        prog = options.subsystem_command[i];
                        cmd = options.subsystem_args[i];
-                       if (!strcmp(INTERNAL_SFTP_NAME, prog)) {
+                       if (strcmp(INTERNAL_SFTP_NAME, prog) == 0) {
                                s->is_subsystem = SUBSYSTEM_INT_SFTP;
-                       } else if (stat(prog, &st) < 0) {
-                               error("subsystem: cannot stat %s: %s", prog,
-                                   strerror(errno));
-                               break;
+                               debug("subsystem: %s", prog);
                        } else {
+                               if (stat(prog, &st) < 0)
+                                       debug("subsystem: cannot stat %s: %s",
+                                           prog, strerror(errno));
                                s->is_subsystem = SUBSYSTEM_EXT;
+                               debug("subsystem: exec() %s", cmd);
                        }
-                       debug("subsystem: exec() %s", cmd);
                        success = do_exec(s, cmd) == 0;
                        break;
                }
@@ -2280,7 +2303,7 @@ session_input_channel_req(Channel *c, const char *rtype)
 }
 
 void
-session_set_fds(Session *s, int fdin, int fdout, int fderr)
+session_set_fds(Session *s, int fdin, int fdout, int fderr, int is_tty)
 {
        if (!compat20)
                fatal("session_set_fds: called for proto != 2.0");
@@ -2293,8 +2316,7 @@ session_set_fds(Session *s, int fdin, int fdout, int fderr)
        channel_set_fds(s->chanid,
            fdout, fdin, fderr,
            fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
-           1,
-           CHAN_SES_WINDOW_DEFAULT);
+           1, is_tty, CHAN_SES_WINDOW_DEFAULT);
 }
 
 /*
This page took 0.148131 seconds and 4 git commands to generate.