1*36e94dc5SPeter Avalos /* $OpenBSD: session.c,v 1.274 2014/07/15 15:54:14 millert Exp $ */ 218de8d7fSPeter Avalos /* 318de8d7fSPeter Avalos * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 418de8d7fSPeter Avalos * All rights reserved 518de8d7fSPeter Avalos * 618de8d7fSPeter Avalos * As far as I am concerned, the code I have written for this software 718de8d7fSPeter Avalos * can be used freely for any purpose. Any derived versions of this 818de8d7fSPeter Avalos * software must be clearly marked as such, and if the derived work is 918de8d7fSPeter Avalos * incompatible with the protocol description in the RFC file, it must be 1018de8d7fSPeter Avalos * called by a name other than "ssh" or "Secure Shell". 1118de8d7fSPeter Avalos * 1218de8d7fSPeter Avalos * SSH2 support by Markus Friedl. 1318de8d7fSPeter Avalos * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 1418de8d7fSPeter Avalos * 1518de8d7fSPeter Avalos * Redistribution and use in source and binary forms, with or without 1618de8d7fSPeter Avalos * modification, are permitted provided that the following conditions 1718de8d7fSPeter Avalos * are met: 1818de8d7fSPeter Avalos * 1. Redistributions of source code must retain the above copyright 1918de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer. 2018de8d7fSPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright 2118de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer in the 2218de8d7fSPeter Avalos * documentation and/or other materials provided with the distribution. 2318de8d7fSPeter Avalos * 2418de8d7fSPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2518de8d7fSPeter Avalos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2618de8d7fSPeter Avalos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2718de8d7fSPeter Avalos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2818de8d7fSPeter Avalos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2918de8d7fSPeter Avalos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3018de8d7fSPeter Avalos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3118de8d7fSPeter Avalos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3218de8d7fSPeter Avalos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3318de8d7fSPeter Avalos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3418de8d7fSPeter Avalos */ 3518de8d7fSPeter Avalos 3618de8d7fSPeter Avalos #include "includes.h" 3718de8d7fSPeter Avalos 3818de8d7fSPeter Avalos #include <sys/types.h> 3918de8d7fSPeter Avalos #include <sys/param.h> 4018de8d7fSPeter Avalos #ifdef HAVE_SYS_STAT_H 4118de8d7fSPeter Avalos # include <sys/stat.h> 4218de8d7fSPeter Avalos #endif 4318de8d7fSPeter Avalos #include <sys/socket.h> 4418de8d7fSPeter Avalos #include <sys/un.h> 4518de8d7fSPeter Avalos #include <sys/wait.h> 4618de8d7fSPeter Avalos 4718de8d7fSPeter Avalos #include <arpa/inet.h> 4818de8d7fSPeter Avalos 4918de8d7fSPeter Avalos #include <errno.h> 50856ea928SPeter Avalos #include <fcntl.h> 5118de8d7fSPeter Avalos #include <grp.h> 52*36e94dc5SPeter Avalos #include <netdb.h> 5318de8d7fSPeter Avalos #ifdef HAVE_PATHS_H 5418de8d7fSPeter Avalos #include <paths.h> 5518de8d7fSPeter Avalos #endif 5618de8d7fSPeter Avalos #include <pwd.h> 5718de8d7fSPeter Avalos #include <signal.h> 5818de8d7fSPeter Avalos #include <stdarg.h> 5918de8d7fSPeter Avalos #include <stdio.h> 6018de8d7fSPeter Avalos #include <stdlib.h> 6118de8d7fSPeter Avalos #include <string.h> 6218de8d7fSPeter Avalos #include <unistd.h> 6318de8d7fSPeter Avalos 6418de8d7fSPeter Avalos #include "openbsd-compat/sys-queue.h" 6518de8d7fSPeter Avalos #include "xmalloc.h" 6618de8d7fSPeter Avalos #include "ssh.h" 6718de8d7fSPeter Avalos #include "ssh1.h" 6818de8d7fSPeter Avalos #include "ssh2.h" 6918de8d7fSPeter Avalos #include "sshpty.h" 7018de8d7fSPeter Avalos #include "packet.h" 7118de8d7fSPeter Avalos #include "buffer.h" 7218de8d7fSPeter Avalos #include "match.h" 7318de8d7fSPeter Avalos #include "uidswap.h" 7418de8d7fSPeter Avalos #include "compat.h" 7518de8d7fSPeter Avalos #include "channels.h" 7618de8d7fSPeter Avalos #include "key.h" 7718de8d7fSPeter Avalos #include "cipher.h" 7818de8d7fSPeter Avalos #ifdef GSSAPI 7918de8d7fSPeter Avalos #include "ssh-gss.h" 8018de8d7fSPeter Avalos #endif 8118de8d7fSPeter Avalos #include "hostfile.h" 8218de8d7fSPeter Avalos #include "auth.h" 8318de8d7fSPeter Avalos #include "auth-options.h" 84*36e94dc5SPeter Avalos #include "authfd.h" 8518de8d7fSPeter Avalos #include "pathnames.h" 8618de8d7fSPeter Avalos #include "log.h" 87*36e94dc5SPeter Avalos #include "misc.h" 8818de8d7fSPeter Avalos #include "servconf.h" 8918de8d7fSPeter Avalos #include "sshlogin.h" 9018de8d7fSPeter Avalos #include "serverloop.h" 9118de8d7fSPeter Avalos #include "canohost.h" 9218de8d7fSPeter Avalos #include "session.h" 9318de8d7fSPeter Avalos #include "kex.h" 9418de8d7fSPeter Avalos #include "monitor_wrap.h" 9518de8d7fSPeter Avalos #include "sftp.h" 9618de8d7fSPeter Avalos 9718de8d7fSPeter Avalos #if defined(KRB5) && defined(USE_AFS) 9818de8d7fSPeter Avalos #include <kafs.h> 9918de8d7fSPeter Avalos #endif 10018de8d7fSPeter Avalos 1011c188a7fSPeter Avalos #ifdef WITH_SELINUX 1021c188a7fSPeter Avalos #include <selinux/selinux.h> 1031c188a7fSPeter Avalos #endif 1041c188a7fSPeter Avalos 105cb5eb4f1SPeter Avalos #define IS_INTERNAL_SFTP(c) \ 106cb5eb4f1SPeter Avalos (!strncmp(c, INTERNAL_SFTP_NAME, sizeof(INTERNAL_SFTP_NAME) - 1) && \ 107cb5eb4f1SPeter Avalos (c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\0' || \ 108cb5eb4f1SPeter Avalos c[sizeof(INTERNAL_SFTP_NAME) - 1] == ' ' || \ 109cb5eb4f1SPeter Avalos c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\t')) 110cb5eb4f1SPeter Avalos 11118de8d7fSPeter Avalos /* func */ 11218de8d7fSPeter Avalos 11318de8d7fSPeter Avalos Session *session_new(void); 114856ea928SPeter Avalos void session_set_fds(Session *, int, int, int, int, int); 11518de8d7fSPeter Avalos void session_pty_cleanup(Session *); 11618de8d7fSPeter Avalos void session_proctitle(Session *); 11718de8d7fSPeter Avalos int session_setup_x11fwd(Session *); 11818de8d7fSPeter Avalos int do_exec_pty(Session *, const char *); 11918de8d7fSPeter Avalos int do_exec_no_pty(Session *, const char *); 12018de8d7fSPeter Avalos int do_exec(Session *, const char *); 12118de8d7fSPeter Avalos void do_login(Session *, const char *); 12218de8d7fSPeter Avalos #ifdef LOGIN_NEEDS_UTMPX 12318de8d7fSPeter Avalos static void do_pre_login(Session *s); 12418de8d7fSPeter Avalos #endif 12518de8d7fSPeter Avalos void do_child(Session *, const char *); 12618de8d7fSPeter Avalos void do_motd(void); 12718de8d7fSPeter Avalos int check_quietlogin(Session *, const char *); 12818de8d7fSPeter Avalos 12918de8d7fSPeter Avalos static void do_authenticated1(Authctxt *); 13018de8d7fSPeter Avalos static void do_authenticated2(Authctxt *); 13118de8d7fSPeter Avalos 13218de8d7fSPeter Avalos static int session_pty_req(Session *); 13318de8d7fSPeter Avalos 13418de8d7fSPeter Avalos /* import */ 13518de8d7fSPeter Avalos extern ServerOptions options; 13618de8d7fSPeter Avalos extern char *__progname; 13718de8d7fSPeter Avalos extern int log_stderr; 13818de8d7fSPeter Avalos extern int debug_flag; 13918de8d7fSPeter Avalos extern u_int utmp_len; 14018de8d7fSPeter Avalos extern int startup_pipe; 14118de8d7fSPeter Avalos extern void destroy_sensitive_data(void); 14218de8d7fSPeter Avalos extern Buffer loginmsg; 14318de8d7fSPeter Avalos 14418de8d7fSPeter Avalos /* original command from peer. */ 14518de8d7fSPeter Avalos const char *original_command = NULL; 14618de8d7fSPeter Avalos 14718de8d7fSPeter Avalos /* data */ 14818de8d7fSPeter Avalos static int sessions_first_unused = -1; 14918de8d7fSPeter Avalos static int sessions_nalloc = 0; 15018de8d7fSPeter Avalos static Session *sessions = NULL; 15118de8d7fSPeter Avalos 15218de8d7fSPeter Avalos #define SUBSYSTEM_NONE 0 15318de8d7fSPeter Avalos #define SUBSYSTEM_EXT 1 15418de8d7fSPeter Avalos #define SUBSYSTEM_INT_SFTP 2 155856ea928SPeter Avalos #define SUBSYSTEM_INT_SFTP_ERROR 3 15618de8d7fSPeter Avalos 15718de8d7fSPeter Avalos #ifdef HAVE_LOGIN_CAP 15818de8d7fSPeter Avalos login_cap_t *lc; 15918de8d7fSPeter Avalos #endif 16018de8d7fSPeter Avalos 16118de8d7fSPeter Avalos static int is_child = 0; 16218de8d7fSPeter Avalos 16318de8d7fSPeter Avalos /* Name and directory of socket for authentication agent forwarding. */ 16418de8d7fSPeter Avalos static char *auth_sock_name = NULL; 16518de8d7fSPeter Avalos static char *auth_sock_dir = NULL; 16618de8d7fSPeter Avalos 16718de8d7fSPeter Avalos /* removes the agent forwarding socket */ 16818de8d7fSPeter Avalos 16918de8d7fSPeter Avalos static void 17018de8d7fSPeter Avalos auth_sock_cleanup_proc(struct passwd *pw) 17118de8d7fSPeter Avalos { 17218de8d7fSPeter Avalos if (auth_sock_name != NULL) { 17318de8d7fSPeter Avalos temporarily_use_uid(pw); 17418de8d7fSPeter Avalos unlink(auth_sock_name); 17518de8d7fSPeter Avalos rmdir(auth_sock_dir); 17618de8d7fSPeter Avalos auth_sock_name = NULL; 17718de8d7fSPeter Avalos restore_uid(); 17818de8d7fSPeter Avalos } 17918de8d7fSPeter Avalos } 18018de8d7fSPeter Avalos 18118de8d7fSPeter Avalos static int 18218de8d7fSPeter Avalos auth_input_request_forwarding(struct passwd * pw) 18318de8d7fSPeter Avalos { 18418de8d7fSPeter Avalos Channel *nc; 18518de8d7fSPeter Avalos int sock = -1; 18618de8d7fSPeter Avalos 18718de8d7fSPeter Avalos if (auth_sock_name != NULL) { 18818de8d7fSPeter Avalos error("authentication forwarding requested twice."); 18918de8d7fSPeter Avalos return 0; 19018de8d7fSPeter Avalos } 19118de8d7fSPeter Avalos 19218de8d7fSPeter Avalos /* Temporarily drop privileged uid for mkdir/bind. */ 19318de8d7fSPeter Avalos temporarily_use_uid(pw); 19418de8d7fSPeter Avalos 19518de8d7fSPeter Avalos /* Allocate a buffer for the socket name, and format the name. */ 19618de8d7fSPeter Avalos auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX"); 19718de8d7fSPeter Avalos 19818de8d7fSPeter Avalos /* Create private directory for socket */ 19918de8d7fSPeter Avalos if (mkdtemp(auth_sock_dir) == NULL) { 20018de8d7fSPeter Avalos packet_send_debug("Agent forwarding disabled: " 20118de8d7fSPeter Avalos "mkdtemp() failed: %.100s", strerror(errno)); 20218de8d7fSPeter Avalos restore_uid(); 203*36e94dc5SPeter Avalos free(auth_sock_dir); 20418de8d7fSPeter Avalos auth_sock_dir = NULL; 20518de8d7fSPeter Avalos goto authsock_err; 20618de8d7fSPeter Avalos } 20718de8d7fSPeter Avalos 20818de8d7fSPeter Avalos xasprintf(&auth_sock_name, "%s/agent.%ld", 20918de8d7fSPeter Avalos auth_sock_dir, (long) getpid()); 21018de8d7fSPeter Avalos 211*36e94dc5SPeter Avalos /* Start a Unix listener on auth_sock_name. */ 212*36e94dc5SPeter Avalos sock = unix_listener(auth_sock_name, SSH_LISTEN_BACKLOG, 0); 21318de8d7fSPeter Avalos 21418de8d7fSPeter Avalos /* Restore the privileged uid. */ 21518de8d7fSPeter Avalos restore_uid(); 21618de8d7fSPeter Avalos 217*36e94dc5SPeter Avalos /* Check for socket/bind/listen failure. */ 218*36e94dc5SPeter Avalos if (sock < 0) 21918de8d7fSPeter Avalos goto authsock_err; 22018de8d7fSPeter Avalos 22118de8d7fSPeter Avalos /* Allocate a channel for the authentication agent socket. */ 22218de8d7fSPeter Avalos nc = channel_new("auth socket", 22318de8d7fSPeter Avalos SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, 22418de8d7fSPeter Avalos CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 22518de8d7fSPeter Avalos 0, "auth socket", 1); 226cb5eb4f1SPeter Avalos nc->path = xstrdup(auth_sock_name); 22718de8d7fSPeter Avalos return 1; 22818de8d7fSPeter Avalos 22918de8d7fSPeter Avalos authsock_err: 230*36e94dc5SPeter Avalos free(auth_sock_name); 23118de8d7fSPeter Avalos if (auth_sock_dir != NULL) { 23218de8d7fSPeter Avalos rmdir(auth_sock_dir); 233*36e94dc5SPeter Avalos free(auth_sock_dir); 23418de8d7fSPeter Avalos } 23518de8d7fSPeter Avalos if (sock != -1) 23618de8d7fSPeter Avalos close(sock); 23718de8d7fSPeter Avalos auth_sock_name = NULL; 23818de8d7fSPeter Avalos auth_sock_dir = NULL; 23918de8d7fSPeter Avalos return 0; 24018de8d7fSPeter Avalos } 24118de8d7fSPeter Avalos 24218de8d7fSPeter Avalos static void 24318de8d7fSPeter Avalos display_loginmsg(void) 24418de8d7fSPeter Avalos { 24518de8d7fSPeter Avalos if (buffer_len(&loginmsg) > 0) { 24618de8d7fSPeter Avalos buffer_append(&loginmsg, "\0", 1); 24718de8d7fSPeter Avalos printf("%s", (char *)buffer_ptr(&loginmsg)); 24818de8d7fSPeter Avalos buffer_clear(&loginmsg); 24918de8d7fSPeter Avalos } 25018de8d7fSPeter Avalos } 25118de8d7fSPeter Avalos 25218de8d7fSPeter Avalos void 25318de8d7fSPeter Avalos do_authenticated(Authctxt *authctxt) 25418de8d7fSPeter Avalos { 25518de8d7fSPeter Avalos setproctitle("%s", authctxt->pw->pw_name); 25618de8d7fSPeter Avalos 25718de8d7fSPeter Avalos /* setup the channel layer */ 258*36e94dc5SPeter Avalos /* XXX - streamlocal? */ 259*36e94dc5SPeter Avalos if (no_port_forwarding_flag || 260*36e94dc5SPeter Avalos (options.allow_tcp_forwarding & FORWARD_LOCAL) == 0) 261*36e94dc5SPeter Avalos channel_disable_adm_local_opens(); 262*36e94dc5SPeter Avalos else 26318de8d7fSPeter Avalos channel_permit_all_opens(); 26418de8d7fSPeter Avalos 265856ea928SPeter Avalos auth_debug_send(); 266856ea928SPeter Avalos 26718de8d7fSPeter Avalos if (compat20) 26818de8d7fSPeter Avalos do_authenticated2(authctxt); 26918de8d7fSPeter Avalos else 27018de8d7fSPeter Avalos do_authenticated1(authctxt); 27118de8d7fSPeter Avalos 27218de8d7fSPeter Avalos do_cleanup(authctxt); 27318de8d7fSPeter Avalos } 27418de8d7fSPeter Avalos 27518de8d7fSPeter Avalos /* 27618de8d7fSPeter Avalos * Prepares for an interactive session. This is called after the user has 27718de8d7fSPeter Avalos * been successfully authenticated. During this message exchange, pseudo 27818de8d7fSPeter Avalos * terminals are allocated, X11, TCP/IP, and authentication agent forwardings 27918de8d7fSPeter Avalos * are requested, etc. 28018de8d7fSPeter Avalos */ 28118de8d7fSPeter Avalos static void 28218de8d7fSPeter Avalos do_authenticated1(Authctxt *authctxt) 28318de8d7fSPeter Avalos { 28418de8d7fSPeter Avalos Session *s; 28518de8d7fSPeter Avalos char *command; 28618de8d7fSPeter Avalos int success, type, screen_flag; 28718de8d7fSPeter Avalos int enable_compression_after_reply = 0; 28818de8d7fSPeter Avalos u_int proto_len, data_len, dlen, compression_level = 0; 28918de8d7fSPeter Avalos 29018de8d7fSPeter Avalos s = session_new(); 29118de8d7fSPeter Avalos if (s == NULL) { 29218de8d7fSPeter Avalos error("no more sessions"); 29318de8d7fSPeter Avalos return; 29418de8d7fSPeter Avalos } 29518de8d7fSPeter Avalos s->authctxt = authctxt; 29618de8d7fSPeter Avalos s->pw = authctxt->pw; 29718de8d7fSPeter Avalos 29818de8d7fSPeter Avalos /* 29918de8d7fSPeter Avalos * We stay in this loop until the client requests to execute a shell 30018de8d7fSPeter Avalos * or a command. 30118de8d7fSPeter Avalos */ 30218de8d7fSPeter Avalos for (;;) { 30318de8d7fSPeter Avalos success = 0; 30418de8d7fSPeter Avalos 30518de8d7fSPeter Avalos /* Get a packet from the client. */ 30618de8d7fSPeter Avalos type = packet_read(); 30718de8d7fSPeter Avalos 30818de8d7fSPeter Avalos /* Process the packet. */ 30918de8d7fSPeter Avalos switch (type) { 31018de8d7fSPeter Avalos case SSH_CMSG_REQUEST_COMPRESSION: 31118de8d7fSPeter Avalos compression_level = packet_get_int(); 31218de8d7fSPeter Avalos packet_check_eom(); 31318de8d7fSPeter Avalos if (compression_level < 1 || compression_level > 9) { 31418de8d7fSPeter Avalos packet_send_debug("Received invalid compression level %d.", 31518de8d7fSPeter Avalos compression_level); 31618de8d7fSPeter Avalos break; 31718de8d7fSPeter Avalos } 31818de8d7fSPeter Avalos if (options.compression == COMP_NONE) { 31918de8d7fSPeter Avalos debug2("compression disabled"); 32018de8d7fSPeter Avalos break; 32118de8d7fSPeter Avalos } 32218de8d7fSPeter Avalos /* Enable compression after we have responded with SUCCESS. */ 32318de8d7fSPeter Avalos enable_compression_after_reply = 1; 32418de8d7fSPeter Avalos success = 1; 32518de8d7fSPeter Avalos break; 32618de8d7fSPeter Avalos 32718de8d7fSPeter Avalos case SSH_CMSG_REQUEST_PTY: 32818de8d7fSPeter Avalos success = session_pty_req(s); 32918de8d7fSPeter Avalos break; 33018de8d7fSPeter Avalos 33118de8d7fSPeter Avalos case SSH_CMSG_X11_REQUEST_FORWARDING: 33218de8d7fSPeter Avalos s->auth_proto = packet_get_string(&proto_len); 33318de8d7fSPeter Avalos s->auth_data = packet_get_string(&data_len); 33418de8d7fSPeter Avalos 33518de8d7fSPeter Avalos screen_flag = packet_get_protocol_flags() & 33618de8d7fSPeter Avalos SSH_PROTOFLAG_SCREEN_NUMBER; 33718de8d7fSPeter Avalos debug2("SSH_PROTOFLAG_SCREEN_NUMBER: %d", screen_flag); 33818de8d7fSPeter Avalos 33918de8d7fSPeter Avalos if (packet_remaining() == 4) { 34018de8d7fSPeter Avalos if (!screen_flag) 34118de8d7fSPeter Avalos debug2("Buggy client: " 34218de8d7fSPeter Avalos "X11 screen flag missing"); 34318de8d7fSPeter Avalos s->screen = packet_get_int(); 34418de8d7fSPeter Avalos } else { 34518de8d7fSPeter Avalos s->screen = 0; 34618de8d7fSPeter Avalos } 34718de8d7fSPeter Avalos packet_check_eom(); 34818de8d7fSPeter Avalos success = session_setup_x11fwd(s); 34918de8d7fSPeter Avalos if (!success) { 350*36e94dc5SPeter Avalos free(s->auth_proto); 351*36e94dc5SPeter Avalos free(s->auth_data); 35218de8d7fSPeter Avalos s->auth_proto = NULL; 35318de8d7fSPeter Avalos s->auth_data = NULL; 35418de8d7fSPeter Avalos } 35518de8d7fSPeter Avalos break; 35618de8d7fSPeter Avalos 35718de8d7fSPeter Avalos case SSH_CMSG_AGENT_REQUEST_FORWARDING: 35818de8d7fSPeter Avalos if (!options.allow_agent_forwarding || 35918de8d7fSPeter Avalos no_agent_forwarding_flag || compat13) { 36018de8d7fSPeter Avalos debug("Authentication agent forwarding not permitted for this authentication."); 36118de8d7fSPeter Avalos break; 36218de8d7fSPeter Avalos } 36318de8d7fSPeter Avalos debug("Received authentication agent forwarding request."); 36418de8d7fSPeter Avalos success = auth_input_request_forwarding(s->pw); 36518de8d7fSPeter Avalos break; 36618de8d7fSPeter Avalos 36718de8d7fSPeter Avalos case SSH_CMSG_PORT_FORWARD_REQUEST: 36818de8d7fSPeter Avalos if (no_port_forwarding_flag) { 36918de8d7fSPeter Avalos debug("Port forwarding not permitted for this authentication."); 37018de8d7fSPeter Avalos break; 37118de8d7fSPeter Avalos } 372*36e94dc5SPeter Avalos if (!(options.allow_tcp_forwarding & FORWARD_REMOTE)) { 37318de8d7fSPeter Avalos debug("Port forwarding not permitted."); 37418de8d7fSPeter Avalos break; 37518de8d7fSPeter Avalos } 37618de8d7fSPeter Avalos debug("Received TCP/IP port forwarding request."); 37718de8d7fSPeter Avalos if (channel_input_port_forward_request(s->pw->pw_uid == 0, 378*36e94dc5SPeter Avalos &options.fwd_opts) < 0) { 37918de8d7fSPeter Avalos debug("Port forwarding failed."); 38018de8d7fSPeter Avalos break; 38118de8d7fSPeter Avalos } 38218de8d7fSPeter Avalos success = 1; 38318de8d7fSPeter Avalos break; 38418de8d7fSPeter Avalos 38518de8d7fSPeter Avalos case SSH_CMSG_MAX_PACKET_SIZE: 38618de8d7fSPeter Avalos if (packet_set_maxsize(packet_get_int()) > 0) 38718de8d7fSPeter Avalos success = 1; 38818de8d7fSPeter Avalos break; 38918de8d7fSPeter Avalos 39018de8d7fSPeter Avalos case SSH_CMSG_EXEC_SHELL: 39118de8d7fSPeter Avalos case SSH_CMSG_EXEC_CMD: 39218de8d7fSPeter Avalos if (type == SSH_CMSG_EXEC_CMD) { 39318de8d7fSPeter Avalos command = packet_get_string(&dlen); 39418de8d7fSPeter Avalos debug("Exec command '%.500s'", command); 39518de8d7fSPeter Avalos if (do_exec(s, command) != 0) 39618de8d7fSPeter Avalos packet_disconnect( 39718de8d7fSPeter Avalos "command execution failed"); 398*36e94dc5SPeter Avalos free(command); 39918de8d7fSPeter Avalos } else { 40018de8d7fSPeter Avalos if (do_exec(s, NULL) != 0) 40118de8d7fSPeter Avalos packet_disconnect( 40218de8d7fSPeter Avalos "shell execution failed"); 40318de8d7fSPeter Avalos } 40418de8d7fSPeter Avalos packet_check_eom(); 40518de8d7fSPeter Avalos session_close(s); 40618de8d7fSPeter Avalos return; 40718de8d7fSPeter Avalos 40818de8d7fSPeter Avalos default: 40918de8d7fSPeter Avalos /* 41018de8d7fSPeter Avalos * Any unknown messages in this phase are ignored, 41118de8d7fSPeter Avalos * and a failure message is returned. 41218de8d7fSPeter Avalos */ 41318de8d7fSPeter Avalos logit("Unknown packet type received after authentication: %d", type); 41418de8d7fSPeter Avalos } 41518de8d7fSPeter Avalos packet_start(success ? SSH_SMSG_SUCCESS : SSH_SMSG_FAILURE); 41618de8d7fSPeter Avalos packet_send(); 41718de8d7fSPeter Avalos packet_write_wait(); 41818de8d7fSPeter Avalos 41918de8d7fSPeter Avalos /* Enable compression now that we have replied if appropriate. */ 42018de8d7fSPeter Avalos if (enable_compression_after_reply) { 42118de8d7fSPeter Avalos enable_compression_after_reply = 0; 42218de8d7fSPeter Avalos packet_start_compression(compression_level); 42318de8d7fSPeter Avalos } 42418de8d7fSPeter Avalos } 42518de8d7fSPeter Avalos } 42618de8d7fSPeter Avalos 427*36e94dc5SPeter Avalos #define USE_PIPES 1 42818de8d7fSPeter Avalos /* 42918de8d7fSPeter Avalos * This is called to fork and execute a command when we have no tty. This 43018de8d7fSPeter Avalos * will call do_child from the child, and server_loop from the parent after 43118de8d7fSPeter Avalos * setting up file descriptors and such. 43218de8d7fSPeter Avalos */ 43318de8d7fSPeter Avalos int 43418de8d7fSPeter Avalos do_exec_no_pty(Session *s, const char *command) 43518de8d7fSPeter Avalos { 43618de8d7fSPeter Avalos pid_t pid; 43718de8d7fSPeter Avalos 43818de8d7fSPeter Avalos #ifdef USE_PIPES 43918de8d7fSPeter Avalos int pin[2], pout[2], perr[2]; 44018de8d7fSPeter Avalos 441856ea928SPeter Avalos if (s == NULL) 442856ea928SPeter Avalos fatal("do_exec_no_pty: no session"); 443856ea928SPeter Avalos 44418de8d7fSPeter Avalos /* Allocate pipes for communicating with the program. */ 44518de8d7fSPeter Avalos if (pipe(pin) < 0) { 44618de8d7fSPeter Avalos error("%s: pipe in: %.100s", __func__, strerror(errno)); 44718de8d7fSPeter Avalos return -1; 44818de8d7fSPeter Avalos } 44918de8d7fSPeter Avalos if (pipe(pout) < 0) { 45018de8d7fSPeter Avalos error("%s: pipe out: %.100s", __func__, strerror(errno)); 45118de8d7fSPeter Avalos close(pin[0]); 45218de8d7fSPeter Avalos close(pin[1]); 45318de8d7fSPeter Avalos return -1; 45418de8d7fSPeter Avalos } 45518de8d7fSPeter Avalos if (pipe(perr) < 0) { 456856ea928SPeter Avalos error("%s: pipe err: %.100s", __func__, 457856ea928SPeter Avalos strerror(errno)); 45818de8d7fSPeter Avalos close(pin[0]); 45918de8d7fSPeter Avalos close(pin[1]); 46018de8d7fSPeter Avalos close(pout[0]); 46118de8d7fSPeter Avalos close(pout[1]); 46218de8d7fSPeter Avalos return -1; 46318de8d7fSPeter Avalos } 46418de8d7fSPeter Avalos #else 46518de8d7fSPeter Avalos int inout[2], err[2]; 46618de8d7fSPeter Avalos 467856ea928SPeter Avalos if (s == NULL) 468856ea928SPeter Avalos fatal("do_exec_no_pty: no session"); 469856ea928SPeter Avalos 47018de8d7fSPeter Avalos /* Uses socket pairs to communicate with the program. */ 47118de8d7fSPeter Avalos if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0) { 47218de8d7fSPeter Avalos error("%s: socketpair #1: %.100s", __func__, strerror(errno)); 47318de8d7fSPeter Avalos return -1; 47418de8d7fSPeter Avalos } 47518de8d7fSPeter Avalos if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) { 476856ea928SPeter Avalos error("%s: socketpair #2: %.100s", __func__, 477856ea928SPeter Avalos strerror(errno)); 47818de8d7fSPeter Avalos close(inout[0]); 47918de8d7fSPeter Avalos close(inout[1]); 48018de8d7fSPeter Avalos return -1; 48118de8d7fSPeter Avalos } 48218de8d7fSPeter Avalos #endif 48318de8d7fSPeter Avalos 48418de8d7fSPeter Avalos session_proctitle(s); 48518de8d7fSPeter Avalos 48618de8d7fSPeter Avalos /* Fork the child. */ 48718de8d7fSPeter Avalos switch ((pid = fork())) { 48818de8d7fSPeter Avalos case -1: 48918de8d7fSPeter Avalos error("%s: fork: %.100s", __func__, strerror(errno)); 49018de8d7fSPeter Avalos #ifdef USE_PIPES 49118de8d7fSPeter Avalos close(pin[0]); 49218de8d7fSPeter Avalos close(pin[1]); 49318de8d7fSPeter Avalos close(pout[0]); 49418de8d7fSPeter Avalos close(pout[1]); 49518de8d7fSPeter Avalos close(perr[0]); 49618de8d7fSPeter Avalos close(perr[1]); 49718de8d7fSPeter Avalos #else 49818de8d7fSPeter Avalos close(inout[0]); 49918de8d7fSPeter Avalos close(inout[1]); 50018de8d7fSPeter Avalos close(err[0]); 50118de8d7fSPeter Avalos close(err[1]); 50218de8d7fSPeter Avalos #endif 50318de8d7fSPeter Avalos return -1; 50418de8d7fSPeter Avalos case 0: 50518de8d7fSPeter Avalos is_child = 1; 50618de8d7fSPeter Avalos 50718de8d7fSPeter Avalos /* Child. Reinitialize the log since the pid has changed. */ 50818de8d7fSPeter Avalos log_init(__progname, options.log_level, 50918de8d7fSPeter Avalos options.log_facility, log_stderr); 51018de8d7fSPeter Avalos 51118de8d7fSPeter Avalos /* 51218de8d7fSPeter Avalos * Create a new session and process group since the 4.4BSD 51318de8d7fSPeter Avalos * setlogin() affects the entire process group. 51418de8d7fSPeter Avalos */ 51518de8d7fSPeter Avalos if (setsid() < 0) 51618de8d7fSPeter Avalos error("setsid failed: %.100s", strerror(errno)); 51718de8d7fSPeter Avalos 51818de8d7fSPeter Avalos #ifdef USE_PIPES 51918de8d7fSPeter Avalos /* 52018de8d7fSPeter Avalos * Redirect stdin. We close the parent side of the socket 52118de8d7fSPeter Avalos * pair, and make the child side the standard input. 52218de8d7fSPeter Avalos */ 52318de8d7fSPeter Avalos close(pin[1]); 52418de8d7fSPeter Avalos if (dup2(pin[0], 0) < 0) 52518de8d7fSPeter Avalos perror("dup2 stdin"); 52618de8d7fSPeter Avalos close(pin[0]); 52718de8d7fSPeter Avalos 52818de8d7fSPeter Avalos /* Redirect stdout. */ 52918de8d7fSPeter Avalos close(pout[0]); 53018de8d7fSPeter Avalos if (dup2(pout[1], 1) < 0) 53118de8d7fSPeter Avalos perror("dup2 stdout"); 53218de8d7fSPeter Avalos close(pout[1]); 53318de8d7fSPeter Avalos 53418de8d7fSPeter Avalos /* Redirect stderr. */ 53518de8d7fSPeter Avalos close(perr[0]); 53618de8d7fSPeter Avalos if (dup2(perr[1], 2) < 0) 53718de8d7fSPeter Avalos perror("dup2 stderr"); 53818de8d7fSPeter Avalos close(perr[1]); 53918de8d7fSPeter Avalos #else 54018de8d7fSPeter Avalos /* 54118de8d7fSPeter Avalos * Redirect stdin, stdout, and stderr. Stdin and stdout will 54218de8d7fSPeter Avalos * use the same socket, as some programs (particularly rdist) 54318de8d7fSPeter Avalos * seem to depend on it. 54418de8d7fSPeter Avalos */ 54518de8d7fSPeter Avalos close(inout[1]); 54618de8d7fSPeter Avalos close(err[1]); 54718de8d7fSPeter Avalos if (dup2(inout[0], 0) < 0) /* stdin */ 54818de8d7fSPeter Avalos perror("dup2 stdin"); 54918de8d7fSPeter Avalos if (dup2(inout[0], 1) < 0) /* stdout (same as stdin) */ 55018de8d7fSPeter Avalos perror("dup2 stdout"); 55118de8d7fSPeter Avalos close(inout[0]); 55218de8d7fSPeter Avalos if (dup2(err[0], 2) < 0) /* stderr */ 55318de8d7fSPeter Avalos perror("dup2 stderr"); 55418de8d7fSPeter Avalos close(err[0]); 55518de8d7fSPeter Avalos #endif 55618de8d7fSPeter Avalos 55718de8d7fSPeter Avalos 55818de8d7fSPeter Avalos #ifdef _UNICOS 55918de8d7fSPeter Avalos cray_init_job(s->pw); /* set up cray jid and tmpdir */ 56018de8d7fSPeter Avalos #endif 56118de8d7fSPeter Avalos 56218de8d7fSPeter Avalos /* Do processing for the child (exec command etc). */ 56318de8d7fSPeter Avalos do_child(s, command); 56418de8d7fSPeter Avalos /* NOTREACHED */ 56518de8d7fSPeter Avalos default: 56618de8d7fSPeter Avalos break; 56718de8d7fSPeter Avalos } 56818de8d7fSPeter Avalos 56918de8d7fSPeter Avalos #ifdef _UNICOS 57018de8d7fSPeter Avalos signal(WJSIGNAL, cray_job_termination_handler); 57118de8d7fSPeter Avalos #endif /* _UNICOS */ 57218de8d7fSPeter Avalos #ifdef HAVE_CYGWIN 57318de8d7fSPeter Avalos cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); 57418de8d7fSPeter Avalos #endif 57518de8d7fSPeter Avalos 57618de8d7fSPeter Avalos s->pid = pid; 57718de8d7fSPeter Avalos /* Set interactive/non-interactive mode. */ 5789f304aafSPeter Avalos packet_set_interactive(s->display != NULL, 5799f304aafSPeter Avalos options.ip_qos_interactive, options.ip_qos_bulk); 58018de8d7fSPeter Avalos 58118de8d7fSPeter Avalos /* 58218de8d7fSPeter Avalos * Clear loginmsg, since it's the child's responsibility to display 58318de8d7fSPeter Avalos * it to the user, otherwise multiple sessions may accumulate 58418de8d7fSPeter Avalos * multiple copies of the login messages. 58518de8d7fSPeter Avalos */ 58618de8d7fSPeter Avalos buffer_clear(&loginmsg); 58718de8d7fSPeter Avalos 58818de8d7fSPeter Avalos #ifdef USE_PIPES 58918de8d7fSPeter Avalos /* We are the parent. Close the child sides of the pipes. */ 59018de8d7fSPeter Avalos close(pin[0]); 59118de8d7fSPeter Avalos close(pout[1]); 59218de8d7fSPeter Avalos close(perr[1]); 59318de8d7fSPeter Avalos 59418de8d7fSPeter Avalos if (compat20) { 595856ea928SPeter Avalos session_set_fds(s, pin[1], pout[0], perr[0], 596856ea928SPeter Avalos s->is_subsystem, 0); 59718de8d7fSPeter Avalos } else { 59818de8d7fSPeter Avalos /* Enter the interactive session. */ 59918de8d7fSPeter Avalos server_loop(pid, pin[1], pout[0], perr[0]); 60018de8d7fSPeter Avalos /* server_loop has closed pin[1], pout[0], and perr[0]. */ 60118de8d7fSPeter Avalos } 60218de8d7fSPeter Avalos #else 60318de8d7fSPeter Avalos /* We are the parent. Close the child sides of the socket pairs. */ 60418de8d7fSPeter Avalos close(inout[0]); 60518de8d7fSPeter Avalos close(err[0]); 60618de8d7fSPeter Avalos 60718de8d7fSPeter Avalos /* 60818de8d7fSPeter Avalos * Enter the interactive session. Note: server_loop must be able to 60918de8d7fSPeter Avalos * handle the case that fdin and fdout are the same. 61018de8d7fSPeter Avalos */ 61118de8d7fSPeter Avalos if (compat20) { 612856ea928SPeter Avalos session_set_fds(s, inout[1], inout[1], err[1], 613856ea928SPeter Avalos s->is_subsystem, 0); 61418de8d7fSPeter Avalos } else { 61518de8d7fSPeter Avalos server_loop(pid, inout[1], inout[1], err[1]); 61618de8d7fSPeter Avalos /* server_loop has closed inout[1] and err[1]. */ 61718de8d7fSPeter Avalos } 61818de8d7fSPeter Avalos #endif 61918de8d7fSPeter Avalos return 0; 62018de8d7fSPeter Avalos } 62118de8d7fSPeter Avalos 62218de8d7fSPeter Avalos /* 62318de8d7fSPeter Avalos * This is called to fork and execute a command when we have a tty. This 62418de8d7fSPeter Avalos * will call do_child from the child, and server_loop from the parent after 62518de8d7fSPeter Avalos * setting up file descriptors, controlling tty, updating wtmp, utmp, 62618de8d7fSPeter Avalos * lastlog, and other such operations. 62718de8d7fSPeter Avalos */ 62818de8d7fSPeter Avalos int 62918de8d7fSPeter Avalos do_exec_pty(Session *s, const char *command) 63018de8d7fSPeter Avalos { 63118de8d7fSPeter Avalos int fdout, ptyfd, ttyfd, ptymaster; 63218de8d7fSPeter Avalos pid_t pid; 63318de8d7fSPeter Avalos 63418de8d7fSPeter Avalos if (s == NULL) 63518de8d7fSPeter Avalos fatal("do_exec_pty: no session"); 63618de8d7fSPeter Avalos ptyfd = s->ptyfd; 63718de8d7fSPeter Avalos ttyfd = s->ttyfd; 63818de8d7fSPeter Avalos 63918de8d7fSPeter Avalos /* 64018de8d7fSPeter Avalos * Create another descriptor of the pty master side for use as the 64118de8d7fSPeter Avalos * standard input. We could use the original descriptor, but this 64218de8d7fSPeter Avalos * simplifies code in server_loop. The descriptor is bidirectional. 64318de8d7fSPeter Avalos * Do this before forking (and cleanup in the child) so as to 64418de8d7fSPeter Avalos * detect and gracefully fail out-of-fd conditions. 64518de8d7fSPeter Avalos */ 64618de8d7fSPeter Avalos if ((fdout = dup(ptyfd)) < 0) { 64718de8d7fSPeter Avalos error("%s: dup #1: %s", __func__, strerror(errno)); 64818de8d7fSPeter Avalos close(ttyfd); 64918de8d7fSPeter Avalos close(ptyfd); 65018de8d7fSPeter Avalos return -1; 65118de8d7fSPeter Avalos } 65218de8d7fSPeter Avalos /* we keep a reference to the pty master */ 65318de8d7fSPeter Avalos if ((ptymaster = dup(ptyfd)) < 0) { 65418de8d7fSPeter Avalos error("%s: dup #2: %s", __func__, strerror(errno)); 65518de8d7fSPeter Avalos close(ttyfd); 65618de8d7fSPeter Avalos close(ptyfd); 65718de8d7fSPeter Avalos close(fdout); 65818de8d7fSPeter Avalos return -1; 65918de8d7fSPeter Avalos } 66018de8d7fSPeter Avalos 66118de8d7fSPeter Avalos /* Fork the child. */ 66218de8d7fSPeter Avalos switch ((pid = fork())) { 66318de8d7fSPeter Avalos case -1: 66418de8d7fSPeter Avalos error("%s: fork: %.100s", __func__, strerror(errno)); 66518de8d7fSPeter Avalos close(fdout); 66618de8d7fSPeter Avalos close(ptymaster); 66718de8d7fSPeter Avalos close(ttyfd); 66818de8d7fSPeter Avalos close(ptyfd); 66918de8d7fSPeter Avalos return -1; 67018de8d7fSPeter Avalos case 0: 67118de8d7fSPeter Avalos is_child = 1; 67218de8d7fSPeter Avalos 67318de8d7fSPeter Avalos close(fdout); 67418de8d7fSPeter Avalos close(ptymaster); 67518de8d7fSPeter Avalos 67618de8d7fSPeter Avalos /* Child. Reinitialize the log because the pid has changed. */ 67718de8d7fSPeter Avalos log_init(__progname, options.log_level, 67818de8d7fSPeter Avalos options.log_facility, log_stderr); 67918de8d7fSPeter Avalos /* Close the master side of the pseudo tty. */ 68018de8d7fSPeter Avalos close(ptyfd); 68118de8d7fSPeter Avalos 68218de8d7fSPeter Avalos /* Make the pseudo tty our controlling tty. */ 68318de8d7fSPeter Avalos pty_make_controlling_tty(&ttyfd, s->tty); 68418de8d7fSPeter Avalos 68518de8d7fSPeter Avalos /* Redirect stdin/stdout/stderr from the pseudo tty. */ 68618de8d7fSPeter Avalos if (dup2(ttyfd, 0) < 0) 68718de8d7fSPeter Avalos error("dup2 stdin: %s", strerror(errno)); 68818de8d7fSPeter Avalos if (dup2(ttyfd, 1) < 0) 68918de8d7fSPeter Avalos error("dup2 stdout: %s", strerror(errno)); 69018de8d7fSPeter Avalos if (dup2(ttyfd, 2) < 0) 69118de8d7fSPeter Avalos error("dup2 stderr: %s", strerror(errno)); 69218de8d7fSPeter Avalos 69318de8d7fSPeter Avalos /* Close the extra descriptor for the pseudo tty. */ 69418de8d7fSPeter Avalos close(ttyfd); 69518de8d7fSPeter Avalos 69618de8d7fSPeter Avalos /* record login, etc. similar to login(1) */ 69718de8d7fSPeter Avalos #ifndef HAVE_OSF_SIA 69818de8d7fSPeter Avalos if (!(options.use_login && command == NULL)) { 69918de8d7fSPeter Avalos #ifdef _UNICOS 70018de8d7fSPeter Avalos cray_init_job(s->pw); /* set up cray jid and tmpdir */ 70118de8d7fSPeter Avalos #endif /* _UNICOS */ 70218de8d7fSPeter Avalos do_login(s, command); 70318de8d7fSPeter Avalos } 70418de8d7fSPeter Avalos # ifdef LOGIN_NEEDS_UTMPX 70518de8d7fSPeter Avalos else 70618de8d7fSPeter Avalos do_pre_login(s); 70718de8d7fSPeter Avalos # endif 70818de8d7fSPeter Avalos #endif 70918de8d7fSPeter Avalos /* 71018de8d7fSPeter Avalos * Do common processing for the child, such as execing 71118de8d7fSPeter Avalos * the command. 71218de8d7fSPeter Avalos */ 71318de8d7fSPeter Avalos do_child(s, command); 71418de8d7fSPeter Avalos /* NOTREACHED */ 71518de8d7fSPeter Avalos default: 71618de8d7fSPeter Avalos break; 71718de8d7fSPeter Avalos } 71818de8d7fSPeter Avalos 71918de8d7fSPeter Avalos #ifdef _UNICOS 72018de8d7fSPeter Avalos signal(WJSIGNAL, cray_job_termination_handler); 72118de8d7fSPeter Avalos #endif /* _UNICOS */ 72218de8d7fSPeter Avalos #ifdef HAVE_CYGWIN 72318de8d7fSPeter Avalos cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); 72418de8d7fSPeter Avalos #endif 72518de8d7fSPeter Avalos 72618de8d7fSPeter Avalos s->pid = pid; 72718de8d7fSPeter Avalos 72818de8d7fSPeter Avalos /* Parent. Close the slave side of the pseudo tty. */ 72918de8d7fSPeter Avalos close(ttyfd); 73018de8d7fSPeter Avalos 73118de8d7fSPeter Avalos /* Enter interactive session. */ 73218de8d7fSPeter Avalos s->ptymaster = ptymaster; 7339f304aafSPeter Avalos packet_set_interactive(1, 7349f304aafSPeter Avalos options.ip_qos_interactive, options.ip_qos_bulk); 73518de8d7fSPeter Avalos if (compat20) { 736856ea928SPeter Avalos session_set_fds(s, ptyfd, fdout, -1, 1, 1); 73718de8d7fSPeter Avalos } else { 73818de8d7fSPeter Avalos server_loop(pid, ptyfd, fdout, -1); 73918de8d7fSPeter Avalos /* server_loop _has_ closed ptyfd and fdout. */ 74018de8d7fSPeter Avalos } 74118de8d7fSPeter Avalos return 0; 74218de8d7fSPeter Avalos } 74318de8d7fSPeter Avalos 74418de8d7fSPeter Avalos #ifdef LOGIN_NEEDS_UTMPX 74518de8d7fSPeter Avalos static void 74618de8d7fSPeter Avalos do_pre_login(Session *s) 74718de8d7fSPeter Avalos { 74818de8d7fSPeter Avalos socklen_t fromlen; 74918de8d7fSPeter Avalos struct sockaddr_storage from; 75018de8d7fSPeter Avalos pid_t pid = getpid(); 75118de8d7fSPeter Avalos 75218de8d7fSPeter Avalos /* 75318de8d7fSPeter Avalos * Get IP address of client. If the connection is not a socket, let 75418de8d7fSPeter Avalos * the address be 0.0.0.0. 75518de8d7fSPeter Avalos */ 75618de8d7fSPeter Avalos memset(&from, 0, sizeof(from)); 75718de8d7fSPeter Avalos fromlen = sizeof(from); 75818de8d7fSPeter Avalos if (packet_connection_is_on_socket()) { 75918de8d7fSPeter Avalos if (getpeername(packet_get_connection_in(), 76018de8d7fSPeter Avalos (struct sockaddr *)&from, &fromlen) < 0) { 76118de8d7fSPeter Avalos debug("getpeername: %.100s", strerror(errno)); 76218de8d7fSPeter Avalos cleanup_exit(255); 76318de8d7fSPeter Avalos } 76418de8d7fSPeter Avalos } 76518de8d7fSPeter Avalos 76618de8d7fSPeter Avalos record_utmp_only(pid, s->tty, s->pw->pw_name, 76718de8d7fSPeter Avalos get_remote_name_or_ip(utmp_len, options.use_dns), 76818de8d7fSPeter Avalos (struct sockaddr *)&from, fromlen); 76918de8d7fSPeter Avalos } 77018de8d7fSPeter Avalos #endif 77118de8d7fSPeter Avalos 77218de8d7fSPeter Avalos /* 77318de8d7fSPeter Avalos * This is called to fork and execute a command. If another command is 77418de8d7fSPeter Avalos * to be forced, execute that instead. 77518de8d7fSPeter Avalos */ 77618de8d7fSPeter Avalos int 77718de8d7fSPeter Avalos do_exec(Session *s, const char *command) 77818de8d7fSPeter Avalos { 77918de8d7fSPeter Avalos int ret; 780*36e94dc5SPeter Avalos const char *forced = NULL; 781*36e94dc5SPeter Avalos char session_type[1024], *tty = NULL; 78218de8d7fSPeter Avalos 78318de8d7fSPeter Avalos if (options.adm_forced_command) { 78418de8d7fSPeter Avalos original_command = command; 78518de8d7fSPeter Avalos command = options.adm_forced_command; 786*36e94dc5SPeter Avalos forced = "(config)"; 78718de8d7fSPeter Avalos } else if (forced_command) { 78818de8d7fSPeter Avalos original_command = command; 78918de8d7fSPeter Avalos command = forced_command; 790*36e94dc5SPeter Avalos forced = "(key-option)"; 791*36e94dc5SPeter Avalos } 792*36e94dc5SPeter Avalos if (forced != NULL) { 793856ea928SPeter Avalos if (IS_INTERNAL_SFTP(command)) { 794856ea928SPeter Avalos s->is_subsystem = s->is_subsystem ? 795856ea928SPeter Avalos SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR; 796856ea928SPeter Avalos } else if (s->is_subsystem) 79718de8d7fSPeter Avalos s->is_subsystem = SUBSYSTEM_EXT; 798*36e94dc5SPeter Avalos snprintf(session_type, sizeof(session_type), 799*36e94dc5SPeter Avalos "forced-command %s '%.900s'", forced, command); 800*36e94dc5SPeter Avalos } else if (s->is_subsystem) { 801*36e94dc5SPeter Avalos snprintf(session_type, sizeof(session_type), 802*36e94dc5SPeter Avalos "subsystem '%.900s'", s->subsys); 803*36e94dc5SPeter Avalos } else if (command == NULL) { 804*36e94dc5SPeter Avalos snprintf(session_type, sizeof(session_type), "shell"); 805*36e94dc5SPeter Avalos } else { 806*36e94dc5SPeter Avalos /* NB. we don't log unforced commands to preserve privacy */ 807*36e94dc5SPeter Avalos snprintf(session_type, sizeof(session_type), "command"); 80818de8d7fSPeter Avalos } 80918de8d7fSPeter Avalos 810*36e94dc5SPeter Avalos if (s->ttyfd != -1) { 811*36e94dc5SPeter Avalos tty = s->tty; 812*36e94dc5SPeter Avalos if (strncmp(tty, "/dev/", 5) == 0) 813*36e94dc5SPeter Avalos tty += 5; 814*36e94dc5SPeter Avalos } 815*36e94dc5SPeter Avalos 816*36e94dc5SPeter Avalos verbose("Starting session: %s%s%s for %s from %.200s port %d", 817*36e94dc5SPeter Avalos session_type, 818*36e94dc5SPeter Avalos tty == NULL ? "" : " on ", 819*36e94dc5SPeter Avalos tty == NULL ? "" : tty, 820*36e94dc5SPeter Avalos s->pw->pw_name, 821*36e94dc5SPeter Avalos get_remote_ipaddr(), 822*36e94dc5SPeter Avalos get_remote_port()); 823*36e94dc5SPeter Avalos 82418de8d7fSPeter Avalos #ifdef SSH_AUDIT_EVENTS 82518de8d7fSPeter Avalos if (command != NULL) 82618de8d7fSPeter Avalos PRIVSEP(audit_run_command(command)); 82718de8d7fSPeter Avalos else if (s->ttyfd == -1) { 82818de8d7fSPeter Avalos char *shell = s->pw->pw_shell; 82918de8d7fSPeter Avalos 83018de8d7fSPeter Avalos if (shell[0] == '\0') /* empty shell means /bin/sh */ 83118de8d7fSPeter Avalos shell =_PATH_BSHELL; 83218de8d7fSPeter Avalos PRIVSEP(audit_run_command(shell)); 83318de8d7fSPeter Avalos } 83418de8d7fSPeter Avalos #endif 83518de8d7fSPeter Avalos if (s->ttyfd != -1) 83618de8d7fSPeter Avalos ret = do_exec_pty(s, command); 83718de8d7fSPeter Avalos else 83818de8d7fSPeter Avalos ret = do_exec_no_pty(s, command); 83918de8d7fSPeter Avalos 84018de8d7fSPeter Avalos original_command = NULL; 84118de8d7fSPeter Avalos 84218de8d7fSPeter Avalos /* 84318de8d7fSPeter Avalos * Clear loginmsg: it's the child's responsibility to display 84418de8d7fSPeter Avalos * it to the user, otherwise multiple sessions may accumulate 84518de8d7fSPeter Avalos * multiple copies of the login messages. 84618de8d7fSPeter Avalos */ 84718de8d7fSPeter Avalos buffer_clear(&loginmsg); 84818de8d7fSPeter Avalos 84918de8d7fSPeter Avalos return ret; 85018de8d7fSPeter Avalos } 85118de8d7fSPeter Avalos 85218de8d7fSPeter Avalos /* administrative, login(1)-like work */ 85318de8d7fSPeter Avalos void 85418de8d7fSPeter Avalos do_login(Session *s, const char *command) 85518de8d7fSPeter Avalos { 85618de8d7fSPeter Avalos socklen_t fromlen; 85718de8d7fSPeter Avalos struct sockaddr_storage from; 85818de8d7fSPeter Avalos struct passwd * pw = s->pw; 85918de8d7fSPeter Avalos pid_t pid = getpid(); 86018de8d7fSPeter Avalos 86118de8d7fSPeter Avalos /* 86218de8d7fSPeter Avalos * Get IP address of client. If the connection is not a socket, let 86318de8d7fSPeter Avalos * the address be 0.0.0.0. 86418de8d7fSPeter Avalos */ 86518de8d7fSPeter Avalos memset(&from, 0, sizeof(from)); 86618de8d7fSPeter Avalos fromlen = sizeof(from); 86718de8d7fSPeter Avalos if (packet_connection_is_on_socket()) { 86818de8d7fSPeter Avalos if (getpeername(packet_get_connection_in(), 86918de8d7fSPeter Avalos (struct sockaddr *)&from, &fromlen) < 0) { 87018de8d7fSPeter Avalos debug("getpeername: %.100s", strerror(errno)); 87118de8d7fSPeter Avalos cleanup_exit(255); 87218de8d7fSPeter Avalos } 87318de8d7fSPeter Avalos } 87418de8d7fSPeter Avalos 87518de8d7fSPeter Avalos /* Record that there was a login on that tty from the remote host. */ 87618de8d7fSPeter Avalos if (!use_privsep) 87718de8d7fSPeter Avalos record_login(pid, s->tty, pw->pw_name, pw->pw_uid, 87818de8d7fSPeter Avalos get_remote_name_or_ip(utmp_len, 87918de8d7fSPeter Avalos options.use_dns), 88018de8d7fSPeter Avalos (struct sockaddr *)&from, fromlen); 88118de8d7fSPeter Avalos 88218de8d7fSPeter Avalos #ifdef USE_PAM 88318de8d7fSPeter Avalos /* 88418de8d7fSPeter Avalos * If password change is needed, do it now. 88518de8d7fSPeter Avalos * This needs to occur before the ~/.hushlogin check. 88618de8d7fSPeter Avalos */ 88718de8d7fSPeter Avalos if (options.use_pam && !use_privsep && s->authctxt->force_pwchange) { 88818de8d7fSPeter Avalos display_loginmsg(); 88918de8d7fSPeter Avalos do_pam_chauthtok(); 89018de8d7fSPeter Avalos s->authctxt->force_pwchange = 0; 89118de8d7fSPeter Avalos /* XXX - signal [net] parent to enable forwardings */ 89218de8d7fSPeter Avalos } 89318de8d7fSPeter Avalos #endif 89418de8d7fSPeter Avalos 89518de8d7fSPeter Avalos if (check_quietlogin(s, command)) 89618de8d7fSPeter Avalos return; 89718de8d7fSPeter Avalos 89818de8d7fSPeter Avalos display_loginmsg(); 89918de8d7fSPeter Avalos 90018de8d7fSPeter Avalos do_motd(); 90118de8d7fSPeter Avalos } 90218de8d7fSPeter Avalos 90318de8d7fSPeter Avalos /* 90418de8d7fSPeter Avalos * Display the message of the day. 90518de8d7fSPeter Avalos */ 90618de8d7fSPeter Avalos void 90718de8d7fSPeter Avalos do_motd(void) 90818de8d7fSPeter Avalos { 90918de8d7fSPeter Avalos FILE *f; 91018de8d7fSPeter Avalos char buf[256]; 91118de8d7fSPeter Avalos 91218de8d7fSPeter Avalos if (options.print_motd) { 91318de8d7fSPeter Avalos #ifdef HAVE_LOGIN_CAP 91418de8d7fSPeter Avalos f = fopen(login_getcapstr(lc, "welcome", "/etc/motd", 91518de8d7fSPeter Avalos "/etc/motd"), "r"); 91618de8d7fSPeter Avalos #else 91718de8d7fSPeter Avalos f = fopen("/etc/motd", "r"); 91818de8d7fSPeter Avalos #endif 91918de8d7fSPeter Avalos if (f) { 92018de8d7fSPeter Avalos while (fgets(buf, sizeof(buf), f)) 92118de8d7fSPeter Avalos fputs(buf, stdout); 92218de8d7fSPeter Avalos fclose(f); 92318de8d7fSPeter Avalos } 92418de8d7fSPeter Avalos } 92518de8d7fSPeter Avalos } 92618de8d7fSPeter Avalos 92718de8d7fSPeter Avalos 92818de8d7fSPeter Avalos /* 92918de8d7fSPeter Avalos * Check for quiet login, either .hushlogin or command given. 93018de8d7fSPeter Avalos */ 93118de8d7fSPeter Avalos int 93218de8d7fSPeter Avalos check_quietlogin(Session *s, const char *command) 93318de8d7fSPeter Avalos { 93418de8d7fSPeter Avalos char buf[256]; 93518de8d7fSPeter Avalos struct passwd *pw = s->pw; 93618de8d7fSPeter Avalos struct stat st; 93718de8d7fSPeter Avalos 93818de8d7fSPeter Avalos /* Return 1 if .hushlogin exists or a command given. */ 93918de8d7fSPeter Avalos if (command != NULL) 94018de8d7fSPeter Avalos return 1; 94118de8d7fSPeter Avalos snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir); 94218de8d7fSPeter Avalos #ifdef HAVE_LOGIN_CAP 94318de8d7fSPeter Avalos if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0) 94418de8d7fSPeter Avalos return 1; 94518de8d7fSPeter Avalos #else 94618de8d7fSPeter Avalos if (stat(buf, &st) >= 0) 94718de8d7fSPeter Avalos return 1; 94818de8d7fSPeter Avalos #endif 94918de8d7fSPeter Avalos return 0; 95018de8d7fSPeter Avalos } 95118de8d7fSPeter Avalos 95218de8d7fSPeter Avalos /* 95318de8d7fSPeter Avalos * Sets the value of the given variable in the environment. If the variable 954cb5eb4f1SPeter Avalos * already exists, its value is overridden. 95518de8d7fSPeter Avalos */ 95618de8d7fSPeter Avalos void 95718de8d7fSPeter Avalos child_set_env(char ***envp, u_int *envsizep, const char *name, 95818de8d7fSPeter Avalos const char *value) 95918de8d7fSPeter Avalos { 96018de8d7fSPeter Avalos char **env; 96118de8d7fSPeter Avalos u_int envsize; 96218de8d7fSPeter Avalos u_int i, namelen; 96318de8d7fSPeter Avalos 964*36e94dc5SPeter Avalos if (strchr(name, '=') != NULL) { 965*36e94dc5SPeter Avalos error("Invalid environment variable \"%.100s\"", name); 966*36e94dc5SPeter Avalos return; 967*36e94dc5SPeter Avalos } 968*36e94dc5SPeter Avalos 96918de8d7fSPeter Avalos /* 97018de8d7fSPeter Avalos * If we're passed an uninitialized list, allocate a single null 97118de8d7fSPeter Avalos * entry before continuing. 97218de8d7fSPeter Avalos */ 97318de8d7fSPeter Avalos if (*envp == NULL && *envsizep == 0) { 97418de8d7fSPeter Avalos *envp = xmalloc(sizeof(char *)); 97518de8d7fSPeter Avalos *envp[0] = NULL; 97618de8d7fSPeter Avalos *envsizep = 1; 97718de8d7fSPeter Avalos } 97818de8d7fSPeter Avalos 97918de8d7fSPeter Avalos /* 98018de8d7fSPeter Avalos * Find the slot where the value should be stored. If the variable 98118de8d7fSPeter Avalos * already exists, we reuse the slot; otherwise we append a new slot 98218de8d7fSPeter Avalos * at the end of the array, expanding if necessary. 98318de8d7fSPeter Avalos */ 98418de8d7fSPeter Avalos env = *envp; 98518de8d7fSPeter Avalos namelen = strlen(name); 98618de8d7fSPeter Avalos for (i = 0; env[i]; i++) 98718de8d7fSPeter Avalos if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=') 98818de8d7fSPeter Avalos break; 98918de8d7fSPeter Avalos if (env[i]) { 99018de8d7fSPeter Avalos /* Reuse the slot. */ 991*36e94dc5SPeter Avalos free(env[i]); 99218de8d7fSPeter Avalos } else { 99318de8d7fSPeter Avalos /* New variable. Expand if necessary. */ 99418de8d7fSPeter Avalos envsize = *envsizep; 99518de8d7fSPeter Avalos if (i >= envsize - 1) { 99618de8d7fSPeter Avalos if (envsize >= 1000) 99718de8d7fSPeter Avalos fatal("child_set_env: too many env vars"); 99818de8d7fSPeter Avalos envsize += 50; 99918de8d7fSPeter Avalos env = (*envp) = xrealloc(env, envsize, sizeof(char *)); 100018de8d7fSPeter Avalos *envsizep = envsize; 100118de8d7fSPeter Avalos } 100218de8d7fSPeter Avalos /* Need to set the NULL pointer at end of array beyond the new slot. */ 100318de8d7fSPeter Avalos env[i + 1] = NULL; 100418de8d7fSPeter Avalos } 100518de8d7fSPeter Avalos 100618de8d7fSPeter Avalos /* Allocate space and format the variable in the appropriate slot. */ 100718de8d7fSPeter Avalos env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1); 100818de8d7fSPeter Avalos snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value); 100918de8d7fSPeter Avalos } 101018de8d7fSPeter Avalos 101118de8d7fSPeter Avalos /* 101218de8d7fSPeter Avalos * Reads environment variables from the given file and adds/overrides them 101318de8d7fSPeter Avalos * into the environment. If the file does not exist, this does nothing. 101418de8d7fSPeter Avalos * Otherwise, it must consist of empty lines, comments (line starts with '#') 101518de8d7fSPeter Avalos * and assignments of the form name=value. No other forms are allowed. 101618de8d7fSPeter Avalos */ 101718de8d7fSPeter Avalos static void 101818de8d7fSPeter Avalos read_environment_file(char ***env, u_int *envsize, 101918de8d7fSPeter Avalos const char *filename) 102018de8d7fSPeter Avalos { 102118de8d7fSPeter Avalos FILE *f; 102218de8d7fSPeter Avalos char buf[4096]; 102318de8d7fSPeter Avalos char *cp, *value; 102418de8d7fSPeter Avalos u_int lineno = 0; 102518de8d7fSPeter Avalos 102618de8d7fSPeter Avalos f = fopen(filename, "r"); 102718de8d7fSPeter Avalos if (!f) 102818de8d7fSPeter Avalos return; 102918de8d7fSPeter Avalos 103018de8d7fSPeter Avalos while (fgets(buf, sizeof(buf), f)) { 103118de8d7fSPeter Avalos if (++lineno > 1000) 103218de8d7fSPeter Avalos fatal("Too many lines in environment file %s", filename); 103318de8d7fSPeter Avalos for (cp = buf; *cp == ' ' || *cp == '\t'; cp++) 103418de8d7fSPeter Avalos ; 103518de8d7fSPeter Avalos if (!*cp || *cp == '#' || *cp == '\n') 103618de8d7fSPeter Avalos continue; 103718de8d7fSPeter Avalos 103818de8d7fSPeter Avalos cp[strcspn(cp, "\n")] = '\0'; 103918de8d7fSPeter Avalos 104018de8d7fSPeter Avalos value = strchr(cp, '='); 104118de8d7fSPeter Avalos if (value == NULL) { 104218de8d7fSPeter Avalos fprintf(stderr, "Bad line %u in %.100s\n", lineno, 104318de8d7fSPeter Avalos filename); 104418de8d7fSPeter Avalos continue; 104518de8d7fSPeter Avalos } 104618de8d7fSPeter Avalos /* 104718de8d7fSPeter Avalos * Replace the equals sign by nul, and advance value to 104818de8d7fSPeter Avalos * the value string. 104918de8d7fSPeter Avalos */ 105018de8d7fSPeter Avalos *value = '\0'; 105118de8d7fSPeter Avalos value++; 105218de8d7fSPeter Avalos child_set_env(env, envsize, cp, value); 105318de8d7fSPeter Avalos } 105418de8d7fSPeter Avalos fclose(f); 105518de8d7fSPeter Avalos } 105618de8d7fSPeter Avalos 105718de8d7fSPeter Avalos #ifdef HAVE_ETC_DEFAULT_LOGIN 105818de8d7fSPeter Avalos /* 105918de8d7fSPeter Avalos * Return named variable from specified environment, or NULL if not present. 106018de8d7fSPeter Avalos */ 106118de8d7fSPeter Avalos static char * 106218de8d7fSPeter Avalos child_get_env(char **env, const char *name) 106318de8d7fSPeter Avalos { 106418de8d7fSPeter Avalos int i; 106518de8d7fSPeter Avalos size_t len; 106618de8d7fSPeter Avalos 106718de8d7fSPeter Avalos len = strlen(name); 106818de8d7fSPeter Avalos for (i=0; env[i] != NULL; i++) 106918de8d7fSPeter Avalos if (strncmp(name, env[i], len) == 0 && env[i][len] == '=') 107018de8d7fSPeter Avalos return(env[i] + len + 1); 107118de8d7fSPeter Avalos return NULL; 107218de8d7fSPeter Avalos } 107318de8d7fSPeter Avalos 107418de8d7fSPeter Avalos /* 107518de8d7fSPeter Avalos * Read /etc/default/login. 107618de8d7fSPeter Avalos * We pick up the PATH (or SUPATH for root) and UMASK. 107718de8d7fSPeter Avalos */ 107818de8d7fSPeter Avalos static void 107918de8d7fSPeter Avalos read_etc_default_login(char ***env, u_int *envsize, uid_t uid) 108018de8d7fSPeter Avalos { 108118de8d7fSPeter Avalos char **tmpenv = NULL, *var; 108218de8d7fSPeter Avalos u_int i, tmpenvsize = 0; 108318de8d7fSPeter Avalos u_long mask; 108418de8d7fSPeter Avalos 108518de8d7fSPeter Avalos /* 108618de8d7fSPeter Avalos * We don't want to copy the whole file to the child's environment, 108718de8d7fSPeter Avalos * so we use a temporary environment and copy the variables we're 108818de8d7fSPeter Avalos * interested in. 108918de8d7fSPeter Avalos */ 109018de8d7fSPeter Avalos read_environment_file(&tmpenv, &tmpenvsize, "/etc/default/login"); 109118de8d7fSPeter Avalos 109218de8d7fSPeter Avalos if (tmpenv == NULL) 109318de8d7fSPeter Avalos return; 109418de8d7fSPeter Avalos 109518de8d7fSPeter Avalos if (uid == 0) 109618de8d7fSPeter Avalos var = child_get_env(tmpenv, "SUPATH"); 109718de8d7fSPeter Avalos else 109818de8d7fSPeter Avalos var = child_get_env(tmpenv, "PATH"); 109918de8d7fSPeter Avalos if (var != NULL) 110018de8d7fSPeter Avalos child_set_env(env, envsize, "PATH", var); 110118de8d7fSPeter Avalos 110218de8d7fSPeter Avalos if ((var = child_get_env(tmpenv, "UMASK")) != NULL) 110318de8d7fSPeter Avalos if (sscanf(var, "%5lo", &mask) == 1) 110418de8d7fSPeter Avalos umask((mode_t)mask); 110518de8d7fSPeter Avalos 110618de8d7fSPeter Avalos for (i = 0; tmpenv[i] != NULL; i++) 1107*36e94dc5SPeter Avalos free(tmpenv[i]); 1108*36e94dc5SPeter Avalos free(tmpenv); 110918de8d7fSPeter Avalos } 111018de8d7fSPeter Avalos #endif /* HAVE_ETC_DEFAULT_LOGIN */ 111118de8d7fSPeter Avalos 111218de8d7fSPeter Avalos void 111318de8d7fSPeter Avalos copy_environment(char **source, char ***env, u_int *envsize) 111418de8d7fSPeter Avalos { 111518de8d7fSPeter Avalos char *var_name, *var_val; 111618de8d7fSPeter Avalos int i; 111718de8d7fSPeter Avalos 111818de8d7fSPeter Avalos if (source == NULL) 111918de8d7fSPeter Avalos return; 112018de8d7fSPeter Avalos 112118de8d7fSPeter Avalos for(i = 0; source[i] != NULL; i++) { 112218de8d7fSPeter Avalos var_name = xstrdup(source[i]); 112318de8d7fSPeter Avalos if ((var_val = strstr(var_name, "=")) == NULL) { 1124*36e94dc5SPeter Avalos free(var_name); 112518de8d7fSPeter Avalos continue; 112618de8d7fSPeter Avalos } 112718de8d7fSPeter Avalos *var_val++ = '\0'; 112818de8d7fSPeter Avalos 112918de8d7fSPeter Avalos debug3("Copy environment: %s=%s", var_name, var_val); 113018de8d7fSPeter Avalos child_set_env(env, envsize, var_name, var_val); 113118de8d7fSPeter Avalos 1132*36e94dc5SPeter Avalos free(var_name); 113318de8d7fSPeter Avalos } 113418de8d7fSPeter Avalos } 113518de8d7fSPeter Avalos 113618de8d7fSPeter Avalos static char ** 113718de8d7fSPeter Avalos do_setup_env(Session *s, const char *shell) 113818de8d7fSPeter Avalos { 113918de8d7fSPeter Avalos char buf[256]; 114018de8d7fSPeter Avalos u_int i, envsize; 114118de8d7fSPeter Avalos char **env, *laddr; 114218de8d7fSPeter Avalos struct passwd *pw = s->pw; 114340c002afSPeter Avalos #if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN) 114418de8d7fSPeter Avalos char *path = NULL; 114518de8d7fSPeter Avalos #endif 114618de8d7fSPeter Avalos 114718de8d7fSPeter Avalos /* Initialize the environment. */ 114818de8d7fSPeter Avalos envsize = 100; 114918de8d7fSPeter Avalos env = xcalloc(envsize, sizeof(char *)); 115018de8d7fSPeter Avalos env[0] = NULL; 115118de8d7fSPeter Avalos 115218de8d7fSPeter Avalos #ifdef HAVE_CYGWIN 115318de8d7fSPeter Avalos /* 115418de8d7fSPeter Avalos * The Windows environment contains some setting which are 115518de8d7fSPeter Avalos * important for a running system. They must not be dropped. 115618de8d7fSPeter Avalos */ 115718de8d7fSPeter Avalos { 115818de8d7fSPeter Avalos char **p; 115918de8d7fSPeter Avalos 116018de8d7fSPeter Avalos p = fetch_windows_environment(); 116118de8d7fSPeter Avalos copy_environment(p, &env, &envsize); 116218de8d7fSPeter Avalos free_windows_environment(p); 116318de8d7fSPeter Avalos } 116418de8d7fSPeter Avalos #endif 116518de8d7fSPeter Avalos 116618de8d7fSPeter Avalos #ifdef GSSAPI 116718de8d7fSPeter Avalos /* Allow any GSSAPI methods that we've used to alter 116818de8d7fSPeter Avalos * the childs environment as they see fit 116918de8d7fSPeter Avalos */ 117018de8d7fSPeter Avalos ssh_gssapi_do_child(&env, &envsize); 117118de8d7fSPeter Avalos #endif 117218de8d7fSPeter Avalos 117318de8d7fSPeter Avalos if (!options.use_login) { 117418de8d7fSPeter Avalos /* Set basic environment. */ 117518de8d7fSPeter Avalos for (i = 0; i < s->num_env; i++) 117618de8d7fSPeter Avalos child_set_env(&env, &envsize, s->env[i].name, 117718de8d7fSPeter Avalos s->env[i].val); 117818de8d7fSPeter Avalos 117918de8d7fSPeter Avalos child_set_env(&env, &envsize, "USER", pw->pw_name); 118018de8d7fSPeter Avalos child_set_env(&env, &envsize, "LOGNAME", pw->pw_name); 118118de8d7fSPeter Avalos #ifdef _AIX 118218de8d7fSPeter Avalos child_set_env(&env, &envsize, "LOGIN", pw->pw_name); 118318de8d7fSPeter Avalos #endif 118418de8d7fSPeter Avalos child_set_env(&env, &envsize, "HOME", pw->pw_dir); 118518de8d7fSPeter Avalos #ifdef HAVE_LOGIN_CAP 118618de8d7fSPeter Avalos if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETPATH) < 0) 118718de8d7fSPeter Avalos child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); 118818de8d7fSPeter Avalos else 118918de8d7fSPeter Avalos child_set_env(&env, &envsize, "PATH", getenv("PATH")); 119018de8d7fSPeter Avalos #else /* HAVE_LOGIN_CAP */ 119118de8d7fSPeter Avalos # ifndef HAVE_CYGWIN 119218de8d7fSPeter Avalos /* 119318de8d7fSPeter Avalos * There's no standard path on Windows. The path contains 119418de8d7fSPeter Avalos * important components pointing to the system directories, 119518de8d7fSPeter Avalos * needed for loading shared libraries. So the path better 119618de8d7fSPeter Avalos * remains intact here. 119718de8d7fSPeter Avalos */ 119818de8d7fSPeter Avalos # ifdef HAVE_ETC_DEFAULT_LOGIN 119918de8d7fSPeter Avalos read_etc_default_login(&env, &envsize, pw->pw_uid); 120018de8d7fSPeter Avalos path = child_get_env(env, "PATH"); 120118de8d7fSPeter Avalos # endif /* HAVE_ETC_DEFAULT_LOGIN */ 120218de8d7fSPeter Avalos if (path == NULL || *path == '\0') { 120318de8d7fSPeter Avalos child_set_env(&env, &envsize, "PATH", 120418de8d7fSPeter Avalos s->pw->pw_uid == 0 ? 120518de8d7fSPeter Avalos SUPERUSER_PATH : _PATH_STDPATH); 120618de8d7fSPeter Avalos } 120718de8d7fSPeter Avalos # endif /* HAVE_CYGWIN */ 120818de8d7fSPeter Avalos #endif /* HAVE_LOGIN_CAP */ 120918de8d7fSPeter Avalos 121018de8d7fSPeter Avalos snprintf(buf, sizeof buf, "%.200s/%.50s", 121118de8d7fSPeter Avalos _PATH_MAILDIR, pw->pw_name); 121218de8d7fSPeter Avalos child_set_env(&env, &envsize, "MAIL", buf); 121318de8d7fSPeter Avalos 121418de8d7fSPeter Avalos /* Normal systems set SHELL by default. */ 121518de8d7fSPeter Avalos child_set_env(&env, &envsize, "SHELL", shell); 121618de8d7fSPeter Avalos } 121718de8d7fSPeter Avalos if (getenv("TZ")) 121818de8d7fSPeter Avalos child_set_env(&env, &envsize, "TZ", getenv("TZ")); 121918de8d7fSPeter Avalos 122018de8d7fSPeter Avalos /* Set custom environment options from RSA authentication. */ 122118de8d7fSPeter Avalos if (!options.use_login) { 122218de8d7fSPeter Avalos while (custom_environment) { 122318de8d7fSPeter Avalos struct envstring *ce = custom_environment; 122418de8d7fSPeter Avalos char *str = ce->s; 122518de8d7fSPeter Avalos 122618de8d7fSPeter Avalos for (i = 0; str[i] != '=' && str[i]; i++) 122718de8d7fSPeter Avalos ; 122818de8d7fSPeter Avalos if (str[i] == '=') { 122918de8d7fSPeter Avalos str[i] = 0; 123018de8d7fSPeter Avalos child_set_env(&env, &envsize, str, str + i + 1); 123118de8d7fSPeter Avalos } 123218de8d7fSPeter Avalos custom_environment = ce->next; 1233*36e94dc5SPeter Avalos free(ce->s); 1234*36e94dc5SPeter Avalos free(ce); 123518de8d7fSPeter Avalos } 123618de8d7fSPeter Avalos } 123718de8d7fSPeter Avalos 123818de8d7fSPeter Avalos /* SSH_CLIENT deprecated */ 123918de8d7fSPeter Avalos snprintf(buf, sizeof buf, "%.50s %d %d", 124018de8d7fSPeter Avalos get_remote_ipaddr(), get_remote_port(), get_local_port()); 124118de8d7fSPeter Avalos child_set_env(&env, &envsize, "SSH_CLIENT", buf); 124218de8d7fSPeter Avalos 124318de8d7fSPeter Avalos laddr = get_local_ipaddr(packet_get_connection_in()); 124418de8d7fSPeter Avalos snprintf(buf, sizeof buf, "%.50s %d %.50s %d", 124518de8d7fSPeter Avalos get_remote_ipaddr(), get_remote_port(), laddr, get_local_port()); 1246*36e94dc5SPeter Avalos free(laddr); 124718de8d7fSPeter Avalos child_set_env(&env, &envsize, "SSH_CONNECTION", buf); 124818de8d7fSPeter Avalos 124918de8d7fSPeter Avalos if (s->ttyfd != -1) 125018de8d7fSPeter Avalos child_set_env(&env, &envsize, "SSH_TTY", s->tty); 125118de8d7fSPeter Avalos if (s->term) 125218de8d7fSPeter Avalos child_set_env(&env, &envsize, "TERM", s->term); 125318de8d7fSPeter Avalos if (s->display) 125418de8d7fSPeter Avalos child_set_env(&env, &envsize, "DISPLAY", s->display); 125518de8d7fSPeter Avalos if (original_command) 125618de8d7fSPeter Avalos child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND", 125718de8d7fSPeter Avalos original_command); 125818de8d7fSPeter Avalos 125918de8d7fSPeter Avalos #ifdef _UNICOS 126018de8d7fSPeter Avalos if (cray_tmpdir[0] != '\0') 126118de8d7fSPeter Avalos child_set_env(&env, &envsize, "TMPDIR", cray_tmpdir); 126218de8d7fSPeter Avalos #endif /* _UNICOS */ 126318de8d7fSPeter Avalos 126418de8d7fSPeter Avalos /* 126518de8d7fSPeter Avalos * Since we clear KRB5CCNAME at startup, if it's set now then it 126618de8d7fSPeter Avalos * must have been set by a native authentication method (eg AIX or 126718de8d7fSPeter Avalos * SIA), so copy it to the child. 126818de8d7fSPeter Avalos */ 126918de8d7fSPeter Avalos { 127018de8d7fSPeter Avalos char *cp; 127118de8d7fSPeter Avalos 127218de8d7fSPeter Avalos if ((cp = getenv("KRB5CCNAME")) != NULL) 127318de8d7fSPeter Avalos child_set_env(&env, &envsize, "KRB5CCNAME", cp); 127418de8d7fSPeter Avalos } 127518de8d7fSPeter Avalos 127618de8d7fSPeter Avalos #ifdef _AIX 127718de8d7fSPeter Avalos { 127818de8d7fSPeter Avalos char *cp; 127918de8d7fSPeter Avalos 128018de8d7fSPeter Avalos if ((cp = getenv("AUTHSTATE")) != NULL) 128118de8d7fSPeter Avalos child_set_env(&env, &envsize, "AUTHSTATE", cp); 128218de8d7fSPeter Avalos read_environment_file(&env, &envsize, "/etc/environment"); 128318de8d7fSPeter Avalos } 128418de8d7fSPeter Avalos #endif 128518de8d7fSPeter Avalos #ifdef KRB5 128618de8d7fSPeter Avalos if (s->authctxt->krb5_ccname) 128718de8d7fSPeter Avalos child_set_env(&env, &envsize, "KRB5CCNAME", 128818de8d7fSPeter Avalos s->authctxt->krb5_ccname); 128918de8d7fSPeter Avalos #endif 129018de8d7fSPeter Avalos #ifdef USE_PAM 129118de8d7fSPeter Avalos /* 129218de8d7fSPeter Avalos * Pull in any environment variables that may have 129318de8d7fSPeter Avalos * been set by PAM. 129418de8d7fSPeter Avalos */ 129518de8d7fSPeter Avalos if (options.use_pam) { 129618de8d7fSPeter Avalos char **p; 129718de8d7fSPeter Avalos 129818de8d7fSPeter Avalos p = fetch_pam_child_environment(); 129918de8d7fSPeter Avalos copy_environment(p, &env, &envsize); 130018de8d7fSPeter Avalos free_pam_environment(p); 130118de8d7fSPeter Avalos 130218de8d7fSPeter Avalos p = fetch_pam_environment(); 130318de8d7fSPeter Avalos copy_environment(p, &env, &envsize); 130418de8d7fSPeter Avalos free_pam_environment(p); 130518de8d7fSPeter Avalos } 130618de8d7fSPeter Avalos #endif /* USE_PAM */ 130718de8d7fSPeter Avalos 130818de8d7fSPeter Avalos if (auth_sock_name != NULL) 130918de8d7fSPeter Avalos child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, 131018de8d7fSPeter Avalos auth_sock_name); 131118de8d7fSPeter Avalos 131218de8d7fSPeter Avalos /* read $HOME/.ssh/environment. */ 131318de8d7fSPeter Avalos if (options.permit_user_env && !options.use_login) { 131418de8d7fSPeter Avalos snprintf(buf, sizeof buf, "%.200s/.ssh/environment", 131518de8d7fSPeter Avalos strcmp(pw->pw_dir, "/") ? pw->pw_dir : ""); 131618de8d7fSPeter Avalos read_environment_file(&env, &envsize, buf); 131718de8d7fSPeter Avalos } 131818de8d7fSPeter Avalos if (debug_flag) { 131918de8d7fSPeter Avalos /* dump the environment */ 132018de8d7fSPeter Avalos fprintf(stderr, "Environment:\n"); 132118de8d7fSPeter Avalos for (i = 0; env[i]; i++) 132218de8d7fSPeter Avalos fprintf(stderr, " %.200s\n", env[i]); 132318de8d7fSPeter Avalos } 132418de8d7fSPeter Avalos return env; 132518de8d7fSPeter Avalos } 132618de8d7fSPeter Avalos 132718de8d7fSPeter Avalos /* 132818de8d7fSPeter Avalos * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found 132918de8d7fSPeter Avalos * first in this order). 133018de8d7fSPeter Avalos */ 133118de8d7fSPeter Avalos static void 133218de8d7fSPeter Avalos do_rc_files(Session *s, const char *shell) 133318de8d7fSPeter Avalos { 133418de8d7fSPeter Avalos FILE *f = NULL; 133518de8d7fSPeter Avalos char cmd[1024]; 133618de8d7fSPeter Avalos int do_xauth; 133718de8d7fSPeter Avalos struct stat st; 133818de8d7fSPeter Avalos 133918de8d7fSPeter Avalos do_xauth = 134018de8d7fSPeter Avalos s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL; 134118de8d7fSPeter Avalos 134218de8d7fSPeter Avalos /* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */ 134318de8d7fSPeter Avalos if (!s->is_subsystem && options.adm_forced_command == NULL && 1344*36e94dc5SPeter Avalos !no_user_rc && options.permit_user_rc && 1345*36e94dc5SPeter Avalos stat(_PATH_SSH_USER_RC, &st) >= 0) { 134618de8d7fSPeter Avalos snprintf(cmd, sizeof cmd, "%s -c '%s %s'", 134718de8d7fSPeter Avalos shell, _PATH_BSHELL, _PATH_SSH_USER_RC); 134818de8d7fSPeter Avalos if (debug_flag) 134918de8d7fSPeter Avalos fprintf(stderr, "Running %s\n", cmd); 135018de8d7fSPeter Avalos f = popen(cmd, "w"); 135118de8d7fSPeter Avalos if (f) { 135218de8d7fSPeter Avalos if (do_xauth) 135318de8d7fSPeter Avalos fprintf(f, "%s %s\n", s->auth_proto, 135418de8d7fSPeter Avalos s->auth_data); 135518de8d7fSPeter Avalos pclose(f); 135618de8d7fSPeter Avalos } else 135718de8d7fSPeter Avalos fprintf(stderr, "Could not run %s\n", 135818de8d7fSPeter Avalos _PATH_SSH_USER_RC); 135918de8d7fSPeter Avalos } else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) { 136018de8d7fSPeter Avalos if (debug_flag) 136118de8d7fSPeter Avalos fprintf(stderr, "Running %s %s\n", _PATH_BSHELL, 136218de8d7fSPeter Avalos _PATH_SSH_SYSTEM_RC); 136318de8d7fSPeter Avalos f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w"); 136418de8d7fSPeter Avalos if (f) { 136518de8d7fSPeter Avalos if (do_xauth) 136618de8d7fSPeter Avalos fprintf(f, "%s %s\n", s->auth_proto, 136718de8d7fSPeter Avalos s->auth_data); 136818de8d7fSPeter Avalos pclose(f); 136918de8d7fSPeter Avalos } else 137018de8d7fSPeter Avalos fprintf(stderr, "Could not run %s\n", 137118de8d7fSPeter Avalos _PATH_SSH_SYSTEM_RC); 137218de8d7fSPeter Avalos } else if (do_xauth && options.xauth_location != NULL) { 137318de8d7fSPeter Avalos /* Add authority data to .Xauthority if appropriate. */ 137418de8d7fSPeter Avalos if (debug_flag) { 137518de8d7fSPeter Avalos fprintf(stderr, 137618de8d7fSPeter Avalos "Running %.500s remove %.100s\n", 137718de8d7fSPeter Avalos options.xauth_location, s->auth_display); 137818de8d7fSPeter Avalos fprintf(stderr, 137918de8d7fSPeter Avalos "%.500s add %.100s %.100s %.100s\n", 138018de8d7fSPeter Avalos options.xauth_location, s->auth_display, 138118de8d7fSPeter Avalos s->auth_proto, s->auth_data); 138218de8d7fSPeter Avalos } 138318de8d7fSPeter Avalos snprintf(cmd, sizeof cmd, "%s -q -", 138418de8d7fSPeter Avalos options.xauth_location); 138518de8d7fSPeter Avalos f = popen(cmd, "w"); 138618de8d7fSPeter Avalos if (f) { 138718de8d7fSPeter Avalos fprintf(f, "remove %s\n", 138818de8d7fSPeter Avalos s->auth_display); 138918de8d7fSPeter Avalos fprintf(f, "add %s %s %s\n", 139018de8d7fSPeter Avalos s->auth_display, s->auth_proto, 139118de8d7fSPeter Avalos s->auth_data); 139218de8d7fSPeter Avalos pclose(f); 139318de8d7fSPeter Avalos } else { 139418de8d7fSPeter Avalos fprintf(stderr, "Could not run %s\n", 139518de8d7fSPeter Avalos cmd); 139618de8d7fSPeter Avalos } 139718de8d7fSPeter Avalos } 139818de8d7fSPeter Avalos } 139918de8d7fSPeter Avalos 140018de8d7fSPeter Avalos static void 140118de8d7fSPeter Avalos do_nologin(struct passwd *pw) 140218de8d7fSPeter Avalos { 140318de8d7fSPeter Avalos FILE *f = NULL; 1404856ea928SPeter Avalos char buf[1024], *nl, *def_nl = _PATH_NOLOGIN; 1405856ea928SPeter Avalos struct stat sb; 140618de8d7fSPeter Avalos 140718de8d7fSPeter Avalos #ifdef HAVE_LOGIN_CAP 140899e85e0dSPeter Avalos if (login_getcapbool(lc, "ignorenologin", 0) || pw->pw_uid == 0) 1409856ea928SPeter Avalos return; 1410856ea928SPeter Avalos nl = login_getcapstr(lc, "nologin", def_nl, def_nl); 141118de8d7fSPeter Avalos #else 1412856ea928SPeter Avalos if (pw->pw_uid == 0) 1413856ea928SPeter Avalos return; 1414856ea928SPeter Avalos nl = def_nl; 141518de8d7fSPeter Avalos #endif 1416856ea928SPeter Avalos if (stat(nl, &sb) == -1) { 1417856ea928SPeter Avalos if (nl != def_nl) 1418*36e94dc5SPeter Avalos free(nl); 1419856ea928SPeter Avalos return; 1420856ea928SPeter Avalos } 1421856ea928SPeter Avalos 1422856ea928SPeter Avalos /* /etc/nologin exists. Print its contents if we can and exit. */ 1423856ea928SPeter Avalos logit("User %.100s not allowed because %s exists", pw->pw_name, nl); 1424856ea928SPeter Avalos if ((f = fopen(nl, "r")) != NULL) { 142518de8d7fSPeter Avalos while (fgets(buf, sizeof(buf), f)) 142618de8d7fSPeter Avalos fputs(buf, stderr); 142718de8d7fSPeter Avalos fclose(f); 142818de8d7fSPeter Avalos } 1429856ea928SPeter Avalos exit(254); 143018de8d7fSPeter Avalos } 143118de8d7fSPeter Avalos 143218de8d7fSPeter Avalos /* 143318de8d7fSPeter Avalos * Chroot into a directory after checking it for safety: all path components 143418de8d7fSPeter Avalos * must be root-owned directories with strict permissions. 143518de8d7fSPeter Avalos */ 143618de8d7fSPeter Avalos static void 143718de8d7fSPeter Avalos safely_chroot(const char *path, uid_t uid) 143818de8d7fSPeter Avalos { 143918de8d7fSPeter Avalos const char *cp; 144018de8d7fSPeter Avalos char component[MAXPATHLEN]; 144118de8d7fSPeter Avalos struct stat st; 144218de8d7fSPeter Avalos 144318de8d7fSPeter Avalos if (*path != '/') 144418de8d7fSPeter Avalos fatal("chroot path does not begin at root"); 144518de8d7fSPeter Avalos if (strlen(path) >= sizeof(component)) 144618de8d7fSPeter Avalos fatal("chroot path too long"); 144718de8d7fSPeter Avalos 144818de8d7fSPeter Avalos /* 144918de8d7fSPeter Avalos * Descend the path, checking that each component is a 145018de8d7fSPeter Avalos * root-owned directory with strict permissions. 145118de8d7fSPeter Avalos */ 145218de8d7fSPeter Avalos for (cp = path; cp != NULL;) { 145318de8d7fSPeter Avalos if ((cp = strchr(cp, '/')) == NULL) 145418de8d7fSPeter Avalos strlcpy(component, path, sizeof(component)); 145518de8d7fSPeter Avalos else { 145618de8d7fSPeter Avalos cp++; 145718de8d7fSPeter Avalos memcpy(component, path, cp - path); 145818de8d7fSPeter Avalos component[cp - path] = '\0'; 145918de8d7fSPeter Avalos } 146018de8d7fSPeter Avalos 146118de8d7fSPeter Avalos debug3("%s: checking '%s'", __func__, component); 146218de8d7fSPeter Avalos 146318de8d7fSPeter Avalos if (stat(component, &st) != 0) 146418de8d7fSPeter Avalos fatal("%s: stat(\"%s\"): %s", __func__, 146518de8d7fSPeter Avalos component, strerror(errno)); 146618de8d7fSPeter Avalos if (st.st_uid != 0 || (st.st_mode & 022) != 0) 146718de8d7fSPeter Avalos fatal("bad ownership or modes for chroot " 146818de8d7fSPeter Avalos "directory %s\"%s\"", 146918de8d7fSPeter Avalos cp == NULL ? "" : "component ", component); 147018de8d7fSPeter Avalos if (!S_ISDIR(st.st_mode)) 147118de8d7fSPeter Avalos fatal("chroot path %s\"%s\" is not a directory", 147218de8d7fSPeter Avalos cp == NULL ? "" : "component ", component); 147318de8d7fSPeter Avalos 147418de8d7fSPeter Avalos } 147518de8d7fSPeter Avalos 147618de8d7fSPeter Avalos if (chdir(path) == -1) 147718de8d7fSPeter Avalos fatal("Unable to chdir to chroot path \"%s\": " 147818de8d7fSPeter Avalos "%s", path, strerror(errno)); 147918de8d7fSPeter Avalos if (chroot(path) == -1) 148018de8d7fSPeter Avalos fatal("chroot(\"%s\"): %s", path, strerror(errno)); 148118de8d7fSPeter Avalos if (chdir("/") == -1) 148218de8d7fSPeter Avalos fatal("%s: chdir(/) after chroot: %s", 148318de8d7fSPeter Avalos __func__, strerror(errno)); 148418de8d7fSPeter Avalos verbose("Changed root directory to \"%s\"", path); 148518de8d7fSPeter Avalos } 148618de8d7fSPeter Avalos 148718de8d7fSPeter Avalos /* Set login name, uid, gid, and groups. */ 148818de8d7fSPeter Avalos void 148918de8d7fSPeter Avalos do_setusercontext(struct passwd *pw) 149018de8d7fSPeter Avalos { 149118de8d7fSPeter Avalos char *chroot_path, *tmp; 1492*36e94dc5SPeter Avalos #ifdef USE_LIBIAF 1493*36e94dc5SPeter Avalos int doing_chroot = 0; 1494*36e94dc5SPeter Avalos #endif 149518de8d7fSPeter Avalos 14969f304aafSPeter Avalos platform_setusercontext(pw); 149718de8d7fSPeter Avalos 14989f304aafSPeter Avalos if (platform_privileged_uidswap()) { 149918de8d7fSPeter Avalos #ifdef HAVE_LOGIN_CAP 150018de8d7fSPeter Avalos if (setusercontext(lc, pw, pw->pw_uid, 150118de8d7fSPeter Avalos (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETUSER))) < 0) { 150218de8d7fSPeter Avalos perror("unable to set user context"); 150318de8d7fSPeter Avalos exit(1); 150418de8d7fSPeter Avalos } 150518de8d7fSPeter Avalos #else 150618de8d7fSPeter Avalos if (setlogin(pw->pw_name) < 0) 150718de8d7fSPeter Avalos error("setlogin failed: %s", strerror(errno)); 150818de8d7fSPeter Avalos if (setgid(pw->pw_gid) < 0) { 150918de8d7fSPeter Avalos perror("setgid"); 151018de8d7fSPeter Avalos exit(1); 151118de8d7fSPeter Avalos } 151218de8d7fSPeter Avalos /* Initialize the group list. */ 151318de8d7fSPeter Avalos if (initgroups(pw->pw_name, pw->pw_gid) < 0) { 151418de8d7fSPeter Avalos perror("initgroups"); 151518de8d7fSPeter Avalos exit(1); 151618de8d7fSPeter Avalos } 151718de8d7fSPeter Avalos endgrent(); 151818de8d7fSPeter Avalos #endif 1519856ea928SPeter Avalos 15209f304aafSPeter Avalos platform_setusercontext_post_groups(pw); 152118de8d7fSPeter Avalos 152218de8d7fSPeter Avalos if (options.chroot_directory != NULL && 152318de8d7fSPeter Avalos strcasecmp(options.chroot_directory, "none") != 0) { 152418de8d7fSPeter Avalos tmp = tilde_expand_filename(options.chroot_directory, 152518de8d7fSPeter Avalos pw->pw_uid); 152618de8d7fSPeter Avalos chroot_path = percent_expand(tmp, "h", pw->pw_dir, 152718de8d7fSPeter Avalos "u", pw->pw_name, (char *)NULL); 152818de8d7fSPeter Avalos safely_chroot(chroot_path, pw->pw_uid); 152918de8d7fSPeter Avalos free(tmp); 153018de8d7fSPeter Avalos free(chroot_path); 1531*36e94dc5SPeter Avalos /* Make sure we don't attempt to chroot again */ 1532*36e94dc5SPeter Avalos free(options.chroot_directory); 1533*36e94dc5SPeter Avalos options.chroot_directory = NULL; 1534*36e94dc5SPeter Avalos #ifdef USE_LIBIAF 1535*36e94dc5SPeter Avalos doing_chroot = 1; 1536*36e94dc5SPeter Avalos #endif 153718de8d7fSPeter Avalos } 153818de8d7fSPeter Avalos 153918de8d7fSPeter Avalos #ifdef HAVE_LOGIN_CAP 154018de8d7fSPeter Avalos if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUSER) < 0) { 154118de8d7fSPeter Avalos perror("unable to set user context (setuser)"); 154218de8d7fSPeter Avalos exit(1); 154318de8d7fSPeter Avalos } 1544*36e94dc5SPeter Avalos /* 1545*36e94dc5SPeter Avalos * FreeBSD's setusercontext() will not apply the user's 1546*36e94dc5SPeter Avalos * own umask setting unless running with the user's UID. 1547*36e94dc5SPeter Avalos */ 1548*36e94dc5SPeter Avalos (void) setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUMASK); 154918de8d7fSPeter Avalos #else 1550*36e94dc5SPeter Avalos # ifdef USE_LIBIAF 1551*36e94dc5SPeter Avalos /* In a chroot environment, the set_id() will always fail; typically 1552*36e94dc5SPeter Avalos * because of the lack of necessary authentication services and runtime 1553*36e94dc5SPeter Avalos * such as ./usr/lib/libiaf.so, ./usr/lib/libpam.so.1, and ./etc/passwd 1554*36e94dc5SPeter Avalos * We skip it in the internal sftp chroot case. 1555*36e94dc5SPeter Avalos * We'll lose auditing and ACLs but permanently_set_uid will 1556*36e94dc5SPeter Avalos * take care of the rest. 1557*36e94dc5SPeter Avalos */ 1558*36e94dc5SPeter Avalos if ((doing_chroot == 0) && set_id(pw->pw_name) != 0) { 1559*36e94dc5SPeter Avalos fatal("set_id(%s) Failed", pw->pw_name); 1560*36e94dc5SPeter Avalos } 1561*36e94dc5SPeter Avalos # endif /* USE_LIBIAF */ 156218de8d7fSPeter Avalos /* Permanently switch to the desired uid. */ 156318de8d7fSPeter Avalos permanently_set_uid(pw); 156418de8d7fSPeter Avalos #endif 1565*36e94dc5SPeter Avalos } else if (options.chroot_directory != NULL && 1566*36e94dc5SPeter Avalos strcasecmp(options.chroot_directory, "none") != 0) { 1567*36e94dc5SPeter Avalos fatal("server lacks privileges to chroot to ChrootDirectory"); 156818de8d7fSPeter Avalos } 156918de8d7fSPeter Avalos 157018de8d7fSPeter Avalos if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) 157118de8d7fSPeter Avalos fatal("Failed to set uids to %u.", (u_int) pw->pw_uid); 157218de8d7fSPeter Avalos } 157318de8d7fSPeter Avalos 157418de8d7fSPeter Avalos static void 157518de8d7fSPeter Avalos do_pwchange(Session *s) 157618de8d7fSPeter Avalos { 157718de8d7fSPeter Avalos fflush(NULL); 157818de8d7fSPeter Avalos fprintf(stderr, "WARNING: Your password has expired.\n"); 157918de8d7fSPeter Avalos if (s->ttyfd != -1) { 158018de8d7fSPeter Avalos fprintf(stderr, 158118de8d7fSPeter Avalos "You must change your password now and login again!\n"); 15821c188a7fSPeter Avalos #ifdef WITH_SELINUX 15831c188a7fSPeter Avalos setexeccon(NULL); 15841c188a7fSPeter Avalos #endif 158518de8d7fSPeter Avalos #ifdef PASSWD_NEEDS_USERNAME 158618de8d7fSPeter Avalos execl(_PATH_PASSWD_PROG, "passwd", s->pw->pw_name, 158718de8d7fSPeter Avalos (char *)NULL); 158818de8d7fSPeter Avalos #else 158918de8d7fSPeter Avalos execl(_PATH_PASSWD_PROG, "passwd", (char *)NULL); 159018de8d7fSPeter Avalos #endif 159118de8d7fSPeter Avalos perror("passwd"); 159218de8d7fSPeter Avalos } else { 159318de8d7fSPeter Avalos fprintf(stderr, 159418de8d7fSPeter Avalos "Password change required but no TTY available.\n"); 159518de8d7fSPeter Avalos } 159618de8d7fSPeter Avalos exit(1); 159718de8d7fSPeter Avalos } 159818de8d7fSPeter Avalos 159918de8d7fSPeter Avalos static void 160018de8d7fSPeter Avalos launch_login(struct passwd *pw, const char *hostname) 160118de8d7fSPeter Avalos { 160218de8d7fSPeter Avalos /* Launch login(1). */ 160318de8d7fSPeter Avalos 160418de8d7fSPeter Avalos execl(LOGIN_PROGRAM, "login", "-h", hostname, 160518de8d7fSPeter Avalos #ifdef xxxLOGIN_NEEDS_TERM 160618de8d7fSPeter Avalos (s->term ? s->term : "unknown"), 160718de8d7fSPeter Avalos #endif /* LOGIN_NEEDS_TERM */ 160818de8d7fSPeter Avalos #ifdef LOGIN_NO_ENDOPT 160918de8d7fSPeter Avalos "-p", "-f", pw->pw_name, (char *)NULL); 161018de8d7fSPeter Avalos #else 161118de8d7fSPeter Avalos "-p", "-f", "--", pw->pw_name, (char *)NULL); 161218de8d7fSPeter Avalos #endif 161318de8d7fSPeter Avalos 161418de8d7fSPeter Avalos /* Login couldn't be executed, die. */ 161518de8d7fSPeter Avalos 161618de8d7fSPeter Avalos perror("login"); 161718de8d7fSPeter Avalos exit(1); 161818de8d7fSPeter Avalos } 161918de8d7fSPeter Avalos 162018de8d7fSPeter Avalos static void 162118de8d7fSPeter Avalos child_close_fds(void) 162218de8d7fSPeter Avalos { 1623*36e94dc5SPeter Avalos extern AuthenticationConnection *auth_conn; 1624*36e94dc5SPeter Avalos 1625*36e94dc5SPeter Avalos if (auth_conn) { 1626*36e94dc5SPeter Avalos ssh_close_authentication_connection(auth_conn); 1627*36e94dc5SPeter Avalos auth_conn = NULL; 1628*36e94dc5SPeter Avalos } 1629*36e94dc5SPeter Avalos 163018de8d7fSPeter Avalos if (packet_get_connection_in() == packet_get_connection_out()) 163118de8d7fSPeter Avalos close(packet_get_connection_in()); 163218de8d7fSPeter Avalos else { 163318de8d7fSPeter Avalos close(packet_get_connection_in()); 163418de8d7fSPeter Avalos close(packet_get_connection_out()); 163518de8d7fSPeter Avalos } 163618de8d7fSPeter Avalos /* 163718de8d7fSPeter Avalos * Close all descriptors related to channels. They will still remain 163818de8d7fSPeter Avalos * open in the parent. 163918de8d7fSPeter Avalos */ 164018de8d7fSPeter Avalos /* XXX better use close-on-exec? -markus */ 164118de8d7fSPeter Avalos channel_close_all(); 164218de8d7fSPeter Avalos 164318de8d7fSPeter Avalos /* 164418de8d7fSPeter Avalos * Close any extra file descriptors. Note that there may still be 164518de8d7fSPeter Avalos * descriptors left by system functions. They will be closed later. 164618de8d7fSPeter Avalos */ 164718de8d7fSPeter Avalos endpwent(); 164818de8d7fSPeter Avalos 164918de8d7fSPeter Avalos /* 165018de8d7fSPeter Avalos * Close any extra open file descriptors so that we don't have them 165118de8d7fSPeter Avalos * hanging around in clients. Note that we want to do this after 165218de8d7fSPeter Avalos * initgroups, because at least on Solaris 2.3 it leaves file 165318de8d7fSPeter Avalos * descriptors open. 165418de8d7fSPeter Avalos */ 16559f304aafSPeter Avalos closefrom(STDERR_FILENO + 1); 165618de8d7fSPeter Avalos } 165718de8d7fSPeter Avalos 165818de8d7fSPeter Avalos /* 165918de8d7fSPeter Avalos * Performs common processing for the child, such as setting up the 166018de8d7fSPeter Avalos * environment, closing extra file descriptors, setting the user and group 166118de8d7fSPeter Avalos * ids, and executing the command or shell. 166218de8d7fSPeter Avalos */ 166318de8d7fSPeter Avalos #define ARGV_MAX 10 166418de8d7fSPeter Avalos void 166518de8d7fSPeter Avalos do_child(Session *s, const char *command) 166618de8d7fSPeter Avalos { 166718de8d7fSPeter Avalos extern char **environ; 166818de8d7fSPeter Avalos char **env; 166918de8d7fSPeter Avalos char *argv[ARGV_MAX]; 167018de8d7fSPeter Avalos const char *shell, *shell0, *hostname = NULL; 167118de8d7fSPeter Avalos struct passwd *pw = s->pw; 167218de8d7fSPeter Avalos int r = 0; 167318de8d7fSPeter Avalos 167418de8d7fSPeter Avalos /* remove hostkey from the child's memory */ 167518de8d7fSPeter Avalos destroy_sensitive_data(); 167618de8d7fSPeter Avalos 167718de8d7fSPeter Avalos /* Force a password change */ 167818de8d7fSPeter Avalos if (s->authctxt->force_pwchange) { 167918de8d7fSPeter Avalos do_setusercontext(pw); 168018de8d7fSPeter Avalos child_close_fds(); 168118de8d7fSPeter Avalos do_pwchange(s); 168218de8d7fSPeter Avalos exit(1); 168318de8d7fSPeter Avalos } 168418de8d7fSPeter Avalos 168518de8d7fSPeter Avalos /* login(1) is only called if we execute the login shell */ 168618de8d7fSPeter Avalos if (options.use_login && command != NULL) 168718de8d7fSPeter Avalos options.use_login = 0; 168818de8d7fSPeter Avalos 168918de8d7fSPeter Avalos #ifdef _UNICOS 169018de8d7fSPeter Avalos cray_setup(pw->pw_uid, pw->pw_name, command); 169118de8d7fSPeter Avalos #endif /* _UNICOS */ 169218de8d7fSPeter Avalos 169318de8d7fSPeter Avalos /* 169418de8d7fSPeter Avalos * Login(1) does this as well, and it needs uid 0 for the "-h" 169518de8d7fSPeter Avalos * switch, so we let login(1) to this for us. 169618de8d7fSPeter Avalos */ 169718de8d7fSPeter Avalos if (!options.use_login) { 169818de8d7fSPeter Avalos #ifdef HAVE_OSF_SIA 169918de8d7fSPeter Avalos session_setup_sia(pw, s->ttyfd == -1 ? NULL : s->tty); 170018de8d7fSPeter Avalos if (!check_quietlogin(s, command)) 170118de8d7fSPeter Avalos do_motd(); 170218de8d7fSPeter Avalos #else /* HAVE_OSF_SIA */ 170318de8d7fSPeter Avalos /* When PAM is enabled we rely on it to do the nologin check */ 170418de8d7fSPeter Avalos if (!options.use_pam) 170518de8d7fSPeter Avalos do_nologin(pw); 170618de8d7fSPeter Avalos do_setusercontext(pw); 170718de8d7fSPeter Avalos /* 170818de8d7fSPeter Avalos * PAM session modules in do_setusercontext may have 170918de8d7fSPeter Avalos * generated messages, so if this in an interactive 171018de8d7fSPeter Avalos * login then display them too. 171118de8d7fSPeter Avalos */ 171218de8d7fSPeter Avalos if (!check_quietlogin(s, command)) 171318de8d7fSPeter Avalos display_loginmsg(); 171418de8d7fSPeter Avalos #endif /* HAVE_OSF_SIA */ 171518de8d7fSPeter Avalos } 171618de8d7fSPeter Avalos 171718de8d7fSPeter Avalos #ifdef USE_PAM 171818de8d7fSPeter Avalos if (options.use_pam && !options.use_login && !is_pam_session_open()) { 171918de8d7fSPeter Avalos debug3("PAM session not opened, exiting"); 172018de8d7fSPeter Avalos display_loginmsg(); 172118de8d7fSPeter Avalos exit(254); 172218de8d7fSPeter Avalos } 172318de8d7fSPeter Avalos #endif 172418de8d7fSPeter Avalos 172518de8d7fSPeter Avalos /* 172618de8d7fSPeter Avalos * Get the shell from the password data. An empty shell field is 172718de8d7fSPeter Avalos * legal, and means /bin/sh. 172818de8d7fSPeter Avalos */ 172918de8d7fSPeter Avalos shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; 173018de8d7fSPeter Avalos 173118de8d7fSPeter Avalos /* 173218de8d7fSPeter Avalos * Make sure $SHELL points to the shell from the password file, 173318de8d7fSPeter Avalos * even if shell is overridden from login.conf 173418de8d7fSPeter Avalos */ 173518de8d7fSPeter Avalos env = do_setup_env(s, shell); 173618de8d7fSPeter Avalos 173718de8d7fSPeter Avalos #ifdef HAVE_LOGIN_CAP 173818de8d7fSPeter Avalos shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell); 173918de8d7fSPeter Avalos #endif 174018de8d7fSPeter Avalos 174118de8d7fSPeter Avalos /* we have to stash the hostname before we close our socket. */ 174218de8d7fSPeter Avalos if (options.use_login) 174318de8d7fSPeter Avalos hostname = get_remote_name_or_ip(utmp_len, 174418de8d7fSPeter Avalos options.use_dns); 174518de8d7fSPeter Avalos /* 174618de8d7fSPeter Avalos * Close the connection descriptors; note that this is the child, and 174718de8d7fSPeter Avalos * the server will still have the socket open, and it is important 174818de8d7fSPeter Avalos * that we do not shutdown it. Note that the descriptors cannot be 174918de8d7fSPeter Avalos * closed before building the environment, as we call 175018de8d7fSPeter Avalos * get_remote_ipaddr there. 175118de8d7fSPeter Avalos */ 175218de8d7fSPeter Avalos child_close_fds(); 175318de8d7fSPeter Avalos 175418de8d7fSPeter Avalos /* 175518de8d7fSPeter Avalos * Must take new environment into use so that .ssh/rc, 175618de8d7fSPeter Avalos * /etc/ssh/sshrc and xauth are run in the proper environment. 175718de8d7fSPeter Avalos */ 175818de8d7fSPeter Avalos environ = env; 175918de8d7fSPeter Avalos 176018de8d7fSPeter Avalos #if defined(KRB5) && defined(USE_AFS) 176118de8d7fSPeter Avalos /* 176218de8d7fSPeter Avalos * At this point, we check to see if AFS is active and if we have 176318de8d7fSPeter Avalos * a valid Kerberos 5 TGT. If so, it seems like a good idea to see 176418de8d7fSPeter Avalos * if we can (and need to) extend the ticket into an AFS token. If 176518de8d7fSPeter Avalos * we don't do this, we run into potential problems if the user's 176618de8d7fSPeter Avalos * home directory is in AFS and it's not world-readable. 176718de8d7fSPeter Avalos */ 176818de8d7fSPeter Avalos 176918de8d7fSPeter Avalos if (options.kerberos_get_afs_token && k_hasafs() && 177018de8d7fSPeter Avalos (s->authctxt->krb5_ctx != NULL)) { 177118de8d7fSPeter Avalos char cell[64]; 177218de8d7fSPeter Avalos 177318de8d7fSPeter Avalos debug("Getting AFS token"); 177418de8d7fSPeter Avalos 177518de8d7fSPeter Avalos k_setpag(); 177618de8d7fSPeter Avalos 177718de8d7fSPeter Avalos if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0) 177818de8d7fSPeter Avalos krb5_afslog(s->authctxt->krb5_ctx, 177918de8d7fSPeter Avalos s->authctxt->krb5_fwd_ccache, cell, NULL); 178018de8d7fSPeter Avalos 178118de8d7fSPeter Avalos krb5_afslog_home(s->authctxt->krb5_ctx, 178218de8d7fSPeter Avalos s->authctxt->krb5_fwd_ccache, NULL, NULL, pw->pw_dir); 178318de8d7fSPeter Avalos } 178418de8d7fSPeter Avalos #endif 178518de8d7fSPeter Avalos 178618de8d7fSPeter Avalos /* Change current directory to the user's home directory. */ 178718de8d7fSPeter Avalos if (chdir(pw->pw_dir) < 0) { 178818de8d7fSPeter Avalos /* Suppress missing homedir warning for chroot case */ 178918de8d7fSPeter Avalos #ifdef HAVE_LOGIN_CAP 179018de8d7fSPeter Avalos r = login_getcapbool(lc, "requirehome", 0); 179118de8d7fSPeter Avalos #endif 1792856ea928SPeter Avalos if (r || options.chroot_directory == NULL || 1793856ea928SPeter Avalos strcasecmp(options.chroot_directory, "none") == 0) 179418de8d7fSPeter Avalos fprintf(stderr, "Could not chdir to home " 179518de8d7fSPeter Avalos "directory %s: %s\n", pw->pw_dir, 179618de8d7fSPeter Avalos strerror(errno)); 179718de8d7fSPeter Avalos if (r) 179818de8d7fSPeter Avalos exit(1); 179918de8d7fSPeter Avalos } 180018de8d7fSPeter Avalos 180118de8d7fSPeter Avalos closefrom(STDERR_FILENO + 1); 180218de8d7fSPeter Avalos 180318de8d7fSPeter Avalos if (!options.use_login) 180418de8d7fSPeter Avalos do_rc_files(s, shell); 180518de8d7fSPeter Avalos 180618de8d7fSPeter Avalos /* restore SIGPIPE for child */ 180718de8d7fSPeter Avalos signal(SIGPIPE, SIG_DFL); 180818de8d7fSPeter Avalos 1809856ea928SPeter Avalos if (s->is_subsystem == SUBSYSTEM_INT_SFTP_ERROR) { 1810856ea928SPeter Avalos printf("This service allows sftp connections only.\n"); 1811856ea928SPeter Avalos fflush(NULL); 1812856ea928SPeter Avalos exit(1); 1813856ea928SPeter Avalos } else if (s->is_subsystem == SUBSYSTEM_INT_SFTP) { 181418de8d7fSPeter Avalos extern int optind, optreset; 181518de8d7fSPeter Avalos int i; 181618de8d7fSPeter Avalos char *p, *args; 181718de8d7fSPeter Avalos 181840c002afSPeter Avalos setproctitle("%s@%s", s->pw->pw_name, INTERNAL_SFTP_NAME); 1819cb5eb4f1SPeter Avalos args = xstrdup(command ? command : "sftp-server"); 182018de8d7fSPeter Avalos for (i = 0, (p = strtok(args, " ")); p; (p = strtok(NULL, " "))) 182118de8d7fSPeter Avalos if (i < ARGV_MAX - 1) 182218de8d7fSPeter Avalos argv[i++] = p; 182318de8d7fSPeter Avalos argv[i] = NULL; 182418de8d7fSPeter Avalos optind = optreset = 1; 182518de8d7fSPeter Avalos __progname = argv[0]; 1826856ea928SPeter Avalos #ifdef WITH_SELINUX 1827856ea928SPeter Avalos ssh_selinux_change_context("sftpd_t"); 1828856ea928SPeter Avalos #endif 182918de8d7fSPeter Avalos exit(sftp_server_main(i, argv, s->pw)); 183018de8d7fSPeter Avalos } 183118de8d7fSPeter Avalos 1832856ea928SPeter Avalos fflush(NULL); 1833856ea928SPeter Avalos 183418de8d7fSPeter Avalos if (options.use_login) { 183518de8d7fSPeter Avalos launch_login(pw, hostname); 183618de8d7fSPeter Avalos /* NEVERREACHED */ 183718de8d7fSPeter Avalos } 183818de8d7fSPeter Avalos 183918de8d7fSPeter Avalos /* Get the last component of the shell name. */ 184018de8d7fSPeter Avalos if ((shell0 = strrchr(shell, '/')) != NULL) 184118de8d7fSPeter Avalos shell0++; 184218de8d7fSPeter Avalos else 184318de8d7fSPeter Avalos shell0 = shell; 184418de8d7fSPeter Avalos 184518de8d7fSPeter Avalos /* 184618de8d7fSPeter Avalos * If we have no command, execute the shell. In this case, the shell 184718de8d7fSPeter Avalos * name to be passed in argv[0] is preceded by '-' to indicate that 184818de8d7fSPeter Avalos * this is a login shell. 184918de8d7fSPeter Avalos */ 185018de8d7fSPeter Avalos if (!command) { 185118de8d7fSPeter Avalos char argv0[256]; 185218de8d7fSPeter Avalos 185318de8d7fSPeter Avalos /* Start the shell. Set initial character to '-'. */ 185418de8d7fSPeter Avalos argv0[0] = '-'; 185518de8d7fSPeter Avalos 185618de8d7fSPeter Avalos if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1) 185718de8d7fSPeter Avalos >= sizeof(argv0) - 1) { 185818de8d7fSPeter Avalos errno = EINVAL; 185918de8d7fSPeter Avalos perror(shell); 186018de8d7fSPeter Avalos exit(1); 186118de8d7fSPeter Avalos } 186218de8d7fSPeter Avalos 186318de8d7fSPeter Avalos /* Execute the shell. */ 186418de8d7fSPeter Avalos argv[0] = argv0; 186518de8d7fSPeter Avalos argv[1] = NULL; 186618de8d7fSPeter Avalos execve(shell, argv, env); 186718de8d7fSPeter Avalos 186818de8d7fSPeter Avalos /* Executing the shell failed. */ 186918de8d7fSPeter Avalos perror(shell); 187018de8d7fSPeter Avalos exit(1); 187118de8d7fSPeter Avalos } 187218de8d7fSPeter Avalos /* 187318de8d7fSPeter Avalos * Execute the command using the user's shell. This uses the -c 187418de8d7fSPeter Avalos * option to execute the command. 187518de8d7fSPeter Avalos */ 187618de8d7fSPeter Avalos argv[0] = (char *) shell0; 187718de8d7fSPeter Avalos argv[1] = "-c"; 187818de8d7fSPeter Avalos argv[2] = (char *) command; 187918de8d7fSPeter Avalos argv[3] = NULL; 188018de8d7fSPeter Avalos execve(shell, argv, env); 188118de8d7fSPeter Avalos perror(shell); 188218de8d7fSPeter Avalos exit(1); 188318de8d7fSPeter Avalos } 188418de8d7fSPeter Avalos 188518de8d7fSPeter Avalos void 188618de8d7fSPeter Avalos session_unused(int id) 188718de8d7fSPeter Avalos { 188818de8d7fSPeter Avalos debug3("%s: session id %d unused", __func__, id); 188918de8d7fSPeter Avalos if (id >= options.max_sessions || 189018de8d7fSPeter Avalos id >= sessions_nalloc) { 189118de8d7fSPeter Avalos fatal("%s: insane session id %d (max %d nalloc %d)", 189218de8d7fSPeter Avalos __func__, id, options.max_sessions, sessions_nalloc); 189318de8d7fSPeter Avalos } 1894*36e94dc5SPeter Avalos memset(&sessions[id], 0, sizeof(*sessions)); 189518de8d7fSPeter Avalos sessions[id].self = id; 189618de8d7fSPeter Avalos sessions[id].used = 0; 189718de8d7fSPeter Avalos sessions[id].chanid = -1; 189818de8d7fSPeter Avalos sessions[id].ptyfd = -1; 189918de8d7fSPeter Avalos sessions[id].ttyfd = -1; 190018de8d7fSPeter Avalos sessions[id].ptymaster = -1; 190118de8d7fSPeter Avalos sessions[id].x11_chanids = NULL; 190218de8d7fSPeter Avalos sessions[id].next_unused = sessions_first_unused; 190318de8d7fSPeter Avalos sessions_first_unused = id; 190418de8d7fSPeter Avalos } 190518de8d7fSPeter Avalos 190618de8d7fSPeter Avalos Session * 190718de8d7fSPeter Avalos session_new(void) 190818de8d7fSPeter Avalos { 190918de8d7fSPeter Avalos Session *s, *tmp; 191018de8d7fSPeter Avalos 191118de8d7fSPeter Avalos if (sessions_first_unused == -1) { 191218de8d7fSPeter Avalos if (sessions_nalloc >= options.max_sessions) 191318de8d7fSPeter Avalos return NULL; 191418de8d7fSPeter Avalos debug2("%s: allocate (allocated %d max %d)", 191518de8d7fSPeter Avalos __func__, sessions_nalloc, options.max_sessions); 191618de8d7fSPeter Avalos tmp = xrealloc(sessions, sessions_nalloc + 1, 191718de8d7fSPeter Avalos sizeof(*sessions)); 191818de8d7fSPeter Avalos if (tmp == NULL) { 191918de8d7fSPeter Avalos error("%s: cannot allocate %d sessions", 192018de8d7fSPeter Avalos __func__, sessions_nalloc + 1); 192118de8d7fSPeter Avalos return NULL; 192218de8d7fSPeter Avalos } 192318de8d7fSPeter Avalos sessions = tmp; 192418de8d7fSPeter Avalos session_unused(sessions_nalloc++); 192518de8d7fSPeter Avalos } 192618de8d7fSPeter Avalos 192718de8d7fSPeter Avalos if (sessions_first_unused >= sessions_nalloc || 192818de8d7fSPeter Avalos sessions_first_unused < 0) { 192918de8d7fSPeter Avalos fatal("%s: insane first_unused %d max %d nalloc %d", 193018de8d7fSPeter Avalos __func__, sessions_first_unused, options.max_sessions, 193118de8d7fSPeter Avalos sessions_nalloc); 193218de8d7fSPeter Avalos } 193318de8d7fSPeter Avalos 193418de8d7fSPeter Avalos s = &sessions[sessions_first_unused]; 193518de8d7fSPeter Avalos if (s->used) { 193618de8d7fSPeter Avalos fatal("%s: session %d already used", 193718de8d7fSPeter Avalos __func__, sessions_first_unused); 193818de8d7fSPeter Avalos } 193918de8d7fSPeter Avalos sessions_first_unused = s->next_unused; 194018de8d7fSPeter Avalos s->used = 1; 194118de8d7fSPeter Avalos s->next_unused = -1; 194218de8d7fSPeter Avalos debug("session_new: session %d", s->self); 194318de8d7fSPeter Avalos 194418de8d7fSPeter Avalos return s; 194518de8d7fSPeter Avalos } 194618de8d7fSPeter Avalos 194718de8d7fSPeter Avalos static void 194818de8d7fSPeter Avalos session_dump(void) 194918de8d7fSPeter Avalos { 195018de8d7fSPeter Avalos int i; 195118de8d7fSPeter Avalos for (i = 0; i < sessions_nalloc; i++) { 195218de8d7fSPeter Avalos Session *s = &sessions[i]; 195318de8d7fSPeter Avalos 195418de8d7fSPeter Avalos debug("dump: used %d next_unused %d session %d %p " 195518de8d7fSPeter Avalos "channel %d pid %ld", 195618de8d7fSPeter Avalos s->used, 195718de8d7fSPeter Avalos s->next_unused, 195818de8d7fSPeter Avalos s->self, 195918de8d7fSPeter Avalos s, 196018de8d7fSPeter Avalos s->chanid, 196118de8d7fSPeter Avalos (long)s->pid); 196218de8d7fSPeter Avalos } 196318de8d7fSPeter Avalos } 196418de8d7fSPeter Avalos 196518de8d7fSPeter Avalos int 196618de8d7fSPeter Avalos session_open(Authctxt *authctxt, int chanid) 196718de8d7fSPeter Avalos { 196818de8d7fSPeter Avalos Session *s = session_new(); 196918de8d7fSPeter Avalos debug("session_open: channel %d", chanid); 197018de8d7fSPeter Avalos if (s == NULL) { 197118de8d7fSPeter Avalos error("no more sessions"); 197218de8d7fSPeter Avalos return 0; 197318de8d7fSPeter Avalos } 197418de8d7fSPeter Avalos s->authctxt = authctxt; 197518de8d7fSPeter Avalos s->pw = authctxt->pw; 197618de8d7fSPeter Avalos if (s->pw == NULL || !authctxt->valid) 197718de8d7fSPeter Avalos fatal("no user for session %d", s->self); 197818de8d7fSPeter Avalos debug("session_open: session %d: link with channel %d", s->self, chanid); 197918de8d7fSPeter Avalos s->chanid = chanid; 198018de8d7fSPeter Avalos return 1; 198118de8d7fSPeter Avalos } 198218de8d7fSPeter Avalos 198318de8d7fSPeter Avalos Session * 198418de8d7fSPeter Avalos session_by_tty(char *tty) 198518de8d7fSPeter Avalos { 198618de8d7fSPeter Avalos int i; 198718de8d7fSPeter Avalos for (i = 0; i < sessions_nalloc; i++) { 198818de8d7fSPeter Avalos Session *s = &sessions[i]; 198918de8d7fSPeter Avalos if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) { 199018de8d7fSPeter Avalos debug("session_by_tty: session %d tty %s", i, tty); 199118de8d7fSPeter Avalos return s; 199218de8d7fSPeter Avalos } 199318de8d7fSPeter Avalos } 199418de8d7fSPeter Avalos debug("session_by_tty: unknown tty %.100s", tty); 199518de8d7fSPeter Avalos session_dump(); 199618de8d7fSPeter Avalos return NULL; 199718de8d7fSPeter Avalos } 199818de8d7fSPeter Avalos 199918de8d7fSPeter Avalos static Session * 200018de8d7fSPeter Avalos session_by_channel(int id) 200118de8d7fSPeter Avalos { 200218de8d7fSPeter Avalos int i; 200318de8d7fSPeter Avalos for (i = 0; i < sessions_nalloc; i++) { 200418de8d7fSPeter Avalos Session *s = &sessions[i]; 200518de8d7fSPeter Avalos if (s->used && s->chanid == id) { 200618de8d7fSPeter Avalos debug("session_by_channel: session %d channel %d", 200718de8d7fSPeter Avalos i, id); 200818de8d7fSPeter Avalos return s; 200918de8d7fSPeter Avalos } 201018de8d7fSPeter Avalos } 201118de8d7fSPeter Avalos debug("session_by_channel: unknown channel %d", id); 201218de8d7fSPeter Avalos session_dump(); 201318de8d7fSPeter Avalos return NULL; 201418de8d7fSPeter Avalos } 201518de8d7fSPeter Avalos 201618de8d7fSPeter Avalos static Session * 201718de8d7fSPeter Avalos session_by_x11_channel(int id) 201818de8d7fSPeter Avalos { 201918de8d7fSPeter Avalos int i, j; 202018de8d7fSPeter Avalos 202118de8d7fSPeter Avalos for (i = 0; i < sessions_nalloc; i++) { 202218de8d7fSPeter Avalos Session *s = &sessions[i]; 202318de8d7fSPeter Avalos 202418de8d7fSPeter Avalos if (s->x11_chanids == NULL || !s->used) 202518de8d7fSPeter Avalos continue; 202618de8d7fSPeter Avalos for (j = 0; s->x11_chanids[j] != -1; j++) { 202718de8d7fSPeter Avalos if (s->x11_chanids[j] == id) { 202818de8d7fSPeter Avalos debug("session_by_x11_channel: session %d " 202918de8d7fSPeter Avalos "channel %d", s->self, id); 203018de8d7fSPeter Avalos return s; 203118de8d7fSPeter Avalos } 203218de8d7fSPeter Avalos } 203318de8d7fSPeter Avalos } 203418de8d7fSPeter Avalos debug("session_by_x11_channel: unknown channel %d", id); 203518de8d7fSPeter Avalos session_dump(); 203618de8d7fSPeter Avalos return NULL; 203718de8d7fSPeter Avalos } 203818de8d7fSPeter Avalos 203918de8d7fSPeter Avalos static Session * 204018de8d7fSPeter Avalos session_by_pid(pid_t pid) 204118de8d7fSPeter Avalos { 204218de8d7fSPeter Avalos int i; 204318de8d7fSPeter Avalos debug("session_by_pid: pid %ld", (long)pid); 204418de8d7fSPeter Avalos for (i = 0; i < sessions_nalloc; i++) { 204518de8d7fSPeter Avalos Session *s = &sessions[i]; 204618de8d7fSPeter Avalos if (s->used && s->pid == pid) 204718de8d7fSPeter Avalos return s; 204818de8d7fSPeter Avalos } 204918de8d7fSPeter Avalos error("session_by_pid: unknown pid %ld", (long)pid); 205018de8d7fSPeter Avalos session_dump(); 205118de8d7fSPeter Avalos return NULL; 205218de8d7fSPeter Avalos } 205318de8d7fSPeter Avalos 205418de8d7fSPeter Avalos static int 205518de8d7fSPeter Avalos session_window_change_req(Session *s) 205618de8d7fSPeter Avalos { 205718de8d7fSPeter Avalos s->col = packet_get_int(); 205818de8d7fSPeter Avalos s->row = packet_get_int(); 205918de8d7fSPeter Avalos s->xpixel = packet_get_int(); 206018de8d7fSPeter Avalos s->ypixel = packet_get_int(); 206118de8d7fSPeter Avalos packet_check_eom(); 206218de8d7fSPeter Avalos pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); 206318de8d7fSPeter Avalos return 1; 206418de8d7fSPeter Avalos } 206518de8d7fSPeter Avalos 206618de8d7fSPeter Avalos static int 206718de8d7fSPeter Avalos session_pty_req(Session *s) 206818de8d7fSPeter Avalos { 206918de8d7fSPeter Avalos u_int len; 207018de8d7fSPeter Avalos int n_bytes; 207118de8d7fSPeter Avalos 2072*36e94dc5SPeter Avalos if (no_pty_flag || !options.permit_tty) { 207318de8d7fSPeter Avalos debug("Allocating a pty not permitted for this authentication."); 207418de8d7fSPeter Avalos return 0; 207518de8d7fSPeter Avalos } 207618de8d7fSPeter Avalos if (s->ttyfd != -1) { 207718de8d7fSPeter Avalos packet_disconnect("Protocol error: you already have a pty."); 207818de8d7fSPeter Avalos return 0; 207918de8d7fSPeter Avalos } 208018de8d7fSPeter Avalos 208118de8d7fSPeter Avalos s->term = packet_get_string(&len); 208218de8d7fSPeter Avalos 208318de8d7fSPeter Avalos if (compat20) { 208418de8d7fSPeter Avalos s->col = packet_get_int(); 208518de8d7fSPeter Avalos s->row = packet_get_int(); 208618de8d7fSPeter Avalos } else { 208718de8d7fSPeter Avalos s->row = packet_get_int(); 208818de8d7fSPeter Avalos s->col = packet_get_int(); 208918de8d7fSPeter Avalos } 209018de8d7fSPeter Avalos s->xpixel = packet_get_int(); 209118de8d7fSPeter Avalos s->ypixel = packet_get_int(); 209218de8d7fSPeter Avalos 209318de8d7fSPeter Avalos if (strcmp(s->term, "") == 0) { 2094*36e94dc5SPeter Avalos free(s->term); 209518de8d7fSPeter Avalos s->term = NULL; 209618de8d7fSPeter Avalos } 209718de8d7fSPeter Avalos 209818de8d7fSPeter Avalos /* Allocate a pty and open it. */ 209918de8d7fSPeter Avalos debug("Allocating pty."); 210018de8d7fSPeter Avalos if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, 210118de8d7fSPeter Avalos sizeof(s->tty)))) { 2102*36e94dc5SPeter Avalos free(s->term); 210318de8d7fSPeter Avalos s->term = NULL; 210418de8d7fSPeter Avalos s->ptyfd = -1; 210518de8d7fSPeter Avalos s->ttyfd = -1; 210618de8d7fSPeter Avalos error("session_pty_req: session %d alloc failed", s->self); 210718de8d7fSPeter Avalos return 0; 210818de8d7fSPeter Avalos } 210918de8d7fSPeter Avalos debug("session_pty_req: session %d alloc %s", s->self, s->tty); 211018de8d7fSPeter Avalos 211118de8d7fSPeter Avalos /* for SSH1 the tty modes length is not given */ 211218de8d7fSPeter Avalos if (!compat20) 211318de8d7fSPeter Avalos n_bytes = packet_remaining(); 211418de8d7fSPeter Avalos tty_parse_modes(s->ttyfd, &n_bytes); 211518de8d7fSPeter Avalos 211618de8d7fSPeter Avalos if (!use_privsep) 211718de8d7fSPeter Avalos pty_setowner(s->pw, s->tty); 211818de8d7fSPeter Avalos 211918de8d7fSPeter Avalos /* Set window size from the packet. */ 212018de8d7fSPeter Avalos pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); 212118de8d7fSPeter Avalos 212218de8d7fSPeter Avalos packet_check_eom(); 212318de8d7fSPeter Avalos session_proctitle(s); 212418de8d7fSPeter Avalos return 1; 212518de8d7fSPeter Avalos } 212618de8d7fSPeter Avalos 212718de8d7fSPeter Avalos static int 212818de8d7fSPeter Avalos session_subsystem_req(Session *s) 212918de8d7fSPeter Avalos { 213018de8d7fSPeter Avalos struct stat st; 213118de8d7fSPeter Avalos u_int len; 213218de8d7fSPeter Avalos int success = 0; 2133*36e94dc5SPeter Avalos char *prog, *cmd; 213418de8d7fSPeter Avalos u_int i; 213518de8d7fSPeter Avalos 2136*36e94dc5SPeter Avalos s->subsys = packet_get_string(&len); 213718de8d7fSPeter Avalos packet_check_eom(); 2138*36e94dc5SPeter Avalos debug2("subsystem request for %.100s by user %s", s->subsys, 2139856ea928SPeter Avalos s->pw->pw_name); 214018de8d7fSPeter Avalos 214118de8d7fSPeter Avalos for (i = 0; i < options.num_subsystems; i++) { 2142*36e94dc5SPeter Avalos if (strcmp(s->subsys, options.subsystem_name[i]) == 0) { 214318de8d7fSPeter Avalos prog = options.subsystem_command[i]; 214418de8d7fSPeter Avalos cmd = options.subsystem_args[i]; 2145856ea928SPeter Avalos if (strcmp(INTERNAL_SFTP_NAME, prog) == 0) { 214618de8d7fSPeter Avalos s->is_subsystem = SUBSYSTEM_INT_SFTP; 2147856ea928SPeter Avalos debug("subsystem: %s", prog); 214818de8d7fSPeter Avalos } else { 2149856ea928SPeter Avalos if (stat(prog, &st) < 0) 2150856ea928SPeter Avalos debug("subsystem: cannot stat %s: %s", 2151856ea928SPeter Avalos prog, strerror(errno)); 215218de8d7fSPeter Avalos s->is_subsystem = SUBSYSTEM_EXT; 215318de8d7fSPeter Avalos debug("subsystem: exec() %s", cmd); 2154856ea928SPeter Avalos } 215518de8d7fSPeter Avalos success = do_exec(s, cmd) == 0; 215618de8d7fSPeter Avalos break; 215718de8d7fSPeter Avalos } 215818de8d7fSPeter Avalos } 215918de8d7fSPeter Avalos 216018de8d7fSPeter Avalos if (!success) 2161*36e94dc5SPeter Avalos logit("subsystem request for %.100s by user %s failed, " 2162*36e94dc5SPeter Avalos "subsystem not found", s->subsys, s->pw->pw_name); 216318de8d7fSPeter Avalos 216418de8d7fSPeter Avalos return success; 216518de8d7fSPeter Avalos } 216618de8d7fSPeter Avalos 216718de8d7fSPeter Avalos static int 216818de8d7fSPeter Avalos session_x11_req(Session *s) 216918de8d7fSPeter Avalos { 217018de8d7fSPeter Avalos int success; 217118de8d7fSPeter Avalos 217218de8d7fSPeter Avalos if (s->auth_proto != NULL || s->auth_data != NULL) { 217318de8d7fSPeter Avalos error("session_x11_req: session %d: " 217418de8d7fSPeter Avalos "x11 forwarding already active", s->self); 217518de8d7fSPeter Avalos return 0; 217618de8d7fSPeter Avalos } 217718de8d7fSPeter Avalos s->single_connection = packet_get_char(); 217818de8d7fSPeter Avalos s->auth_proto = packet_get_string(NULL); 217918de8d7fSPeter Avalos s->auth_data = packet_get_string(NULL); 218018de8d7fSPeter Avalos s->screen = packet_get_int(); 218118de8d7fSPeter Avalos packet_check_eom(); 218218de8d7fSPeter Avalos 218318de8d7fSPeter Avalos success = session_setup_x11fwd(s); 218418de8d7fSPeter Avalos if (!success) { 2185*36e94dc5SPeter Avalos free(s->auth_proto); 2186*36e94dc5SPeter Avalos free(s->auth_data); 218718de8d7fSPeter Avalos s->auth_proto = NULL; 218818de8d7fSPeter Avalos s->auth_data = NULL; 218918de8d7fSPeter Avalos } 219018de8d7fSPeter Avalos return success; 219118de8d7fSPeter Avalos } 219218de8d7fSPeter Avalos 219318de8d7fSPeter Avalos static int 219418de8d7fSPeter Avalos session_shell_req(Session *s) 219518de8d7fSPeter Avalos { 219618de8d7fSPeter Avalos packet_check_eom(); 219718de8d7fSPeter Avalos return do_exec(s, NULL) == 0; 219818de8d7fSPeter Avalos } 219918de8d7fSPeter Avalos 220018de8d7fSPeter Avalos static int 220118de8d7fSPeter Avalos session_exec_req(Session *s) 220218de8d7fSPeter Avalos { 220318de8d7fSPeter Avalos u_int len, success; 220418de8d7fSPeter Avalos 220518de8d7fSPeter Avalos char *command = packet_get_string(&len); 220618de8d7fSPeter Avalos packet_check_eom(); 220718de8d7fSPeter Avalos success = do_exec(s, command) == 0; 2208*36e94dc5SPeter Avalos free(command); 220918de8d7fSPeter Avalos return success; 221018de8d7fSPeter Avalos } 221118de8d7fSPeter Avalos 221218de8d7fSPeter Avalos static int 221318de8d7fSPeter Avalos session_break_req(Session *s) 221418de8d7fSPeter Avalos { 221518de8d7fSPeter Avalos 221618de8d7fSPeter Avalos packet_get_int(); /* ignored */ 221718de8d7fSPeter Avalos packet_check_eom(); 221818de8d7fSPeter Avalos 221999e85e0dSPeter Avalos if (s->ptymaster == -1 || tcsendbreak(s->ptymaster, 0) < 0) 222018de8d7fSPeter Avalos return 0; 222118de8d7fSPeter Avalos return 1; 222218de8d7fSPeter Avalos } 222318de8d7fSPeter Avalos 222418de8d7fSPeter Avalos static int 222518de8d7fSPeter Avalos session_env_req(Session *s) 222618de8d7fSPeter Avalos { 222718de8d7fSPeter Avalos char *name, *val; 222818de8d7fSPeter Avalos u_int name_len, val_len, i; 222918de8d7fSPeter Avalos 2230*36e94dc5SPeter Avalos name = packet_get_cstring(&name_len); 2231*36e94dc5SPeter Avalos val = packet_get_cstring(&val_len); 223218de8d7fSPeter Avalos packet_check_eom(); 223318de8d7fSPeter Avalos 223418de8d7fSPeter Avalos /* Don't set too many environment variables */ 223518de8d7fSPeter Avalos if (s->num_env > 128) { 223618de8d7fSPeter Avalos debug2("Ignoring env request %s: too many env vars", name); 223718de8d7fSPeter Avalos goto fail; 223818de8d7fSPeter Avalos } 223918de8d7fSPeter Avalos 224018de8d7fSPeter Avalos for (i = 0; i < options.num_accept_env; i++) { 224118de8d7fSPeter Avalos if (match_pattern(name, options.accept_env[i])) { 224218de8d7fSPeter Avalos debug2("Setting env %d: %s=%s", s->num_env, name, val); 224318de8d7fSPeter Avalos s->env = xrealloc(s->env, s->num_env + 1, 224418de8d7fSPeter Avalos sizeof(*s->env)); 224518de8d7fSPeter Avalos s->env[s->num_env].name = name; 224618de8d7fSPeter Avalos s->env[s->num_env].val = val; 224718de8d7fSPeter Avalos s->num_env++; 224818de8d7fSPeter Avalos return (1); 224918de8d7fSPeter Avalos } 225018de8d7fSPeter Avalos } 225118de8d7fSPeter Avalos debug2("Ignoring env request %s: disallowed name", name); 225218de8d7fSPeter Avalos 225318de8d7fSPeter Avalos fail: 2254*36e94dc5SPeter Avalos free(name); 2255*36e94dc5SPeter Avalos free(val); 225618de8d7fSPeter Avalos return (0); 225718de8d7fSPeter Avalos } 225818de8d7fSPeter Avalos 225918de8d7fSPeter Avalos static int 226018de8d7fSPeter Avalos session_auth_agent_req(Session *s) 226118de8d7fSPeter Avalos { 226218de8d7fSPeter Avalos static int called = 0; 226318de8d7fSPeter Avalos packet_check_eom(); 226418de8d7fSPeter Avalos if (no_agent_forwarding_flag || !options.allow_agent_forwarding) { 226518de8d7fSPeter Avalos debug("session_auth_agent_req: no_agent_forwarding_flag"); 226618de8d7fSPeter Avalos return 0; 226718de8d7fSPeter Avalos } 226818de8d7fSPeter Avalos if (called) { 226918de8d7fSPeter Avalos return 0; 227018de8d7fSPeter Avalos } else { 227118de8d7fSPeter Avalos called = 1; 227218de8d7fSPeter Avalos return auth_input_request_forwarding(s->pw); 227318de8d7fSPeter Avalos } 227418de8d7fSPeter Avalos } 227518de8d7fSPeter Avalos 227618de8d7fSPeter Avalos int 227718de8d7fSPeter Avalos session_input_channel_req(Channel *c, const char *rtype) 227818de8d7fSPeter Avalos { 227918de8d7fSPeter Avalos int success = 0; 228018de8d7fSPeter Avalos Session *s; 228118de8d7fSPeter Avalos 228218de8d7fSPeter Avalos if ((s = session_by_channel(c->self)) == NULL) { 228318de8d7fSPeter Avalos logit("session_input_channel_req: no session %d req %.100s", 228418de8d7fSPeter Avalos c->self, rtype); 228518de8d7fSPeter Avalos return 0; 228618de8d7fSPeter Avalos } 228718de8d7fSPeter Avalos debug("session_input_channel_req: session %d req %s", s->self, rtype); 228818de8d7fSPeter Avalos 228918de8d7fSPeter Avalos /* 229018de8d7fSPeter Avalos * a session is in LARVAL state until a shell, a command 229118de8d7fSPeter Avalos * or a subsystem is executed 229218de8d7fSPeter Avalos */ 229318de8d7fSPeter Avalos if (c->type == SSH_CHANNEL_LARVAL) { 229418de8d7fSPeter Avalos if (strcmp(rtype, "shell") == 0) { 229518de8d7fSPeter Avalos success = session_shell_req(s); 229618de8d7fSPeter Avalos } else if (strcmp(rtype, "exec") == 0) { 229718de8d7fSPeter Avalos success = session_exec_req(s); 229818de8d7fSPeter Avalos } else if (strcmp(rtype, "pty-req") == 0) { 229918de8d7fSPeter Avalos success = session_pty_req(s); 230018de8d7fSPeter Avalos } else if (strcmp(rtype, "x11-req") == 0) { 230118de8d7fSPeter Avalos success = session_x11_req(s); 230218de8d7fSPeter Avalos } else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) { 230318de8d7fSPeter Avalos success = session_auth_agent_req(s); 230418de8d7fSPeter Avalos } else if (strcmp(rtype, "subsystem") == 0) { 230518de8d7fSPeter Avalos success = session_subsystem_req(s); 230618de8d7fSPeter Avalos } else if (strcmp(rtype, "env") == 0) { 230718de8d7fSPeter Avalos success = session_env_req(s); 230818de8d7fSPeter Avalos } 230918de8d7fSPeter Avalos } 231018de8d7fSPeter Avalos if (strcmp(rtype, "window-change") == 0) { 231118de8d7fSPeter Avalos success = session_window_change_req(s); 231218de8d7fSPeter Avalos } else if (strcmp(rtype, "break") == 0) { 231318de8d7fSPeter Avalos success = session_break_req(s); 231418de8d7fSPeter Avalos } 231518de8d7fSPeter Avalos 231618de8d7fSPeter Avalos return success; 231718de8d7fSPeter Avalos } 231818de8d7fSPeter Avalos 231918de8d7fSPeter Avalos void 2320856ea928SPeter Avalos session_set_fds(Session *s, int fdin, int fdout, int fderr, int ignore_fderr, 2321856ea928SPeter Avalos int is_tty) 232218de8d7fSPeter Avalos { 232318de8d7fSPeter Avalos if (!compat20) 232418de8d7fSPeter Avalos fatal("session_set_fds: called for proto != 2.0"); 232518de8d7fSPeter Avalos /* 232618de8d7fSPeter Avalos * now that have a child and a pipe to the child, 232718de8d7fSPeter Avalos * we can activate our channel and register the fd's 232818de8d7fSPeter Avalos */ 232918de8d7fSPeter Avalos if (s->chanid == -1) 233018de8d7fSPeter Avalos fatal("no channel for session %d", s->self); 233118de8d7fSPeter Avalos channel_set_fds(s->chanid, 233218de8d7fSPeter Avalos fdout, fdin, fderr, 2333856ea928SPeter Avalos ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, 233418de8d7fSPeter Avalos 1, is_tty, CHAN_SES_WINDOW_DEFAULT); 233518de8d7fSPeter Avalos } 233618de8d7fSPeter Avalos 233718de8d7fSPeter Avalos /* 233818de8d7fSPeter Avalos * Function to perform pty cleanup. Also called if we get aborted abnormally 233918de8d7fSPeter Avalos * (e.g., due to a dropped connection). 234018de8d7fSPeter Avalos */ 234118de8d7fSPeter Avalos void 234218de8d7fSPeter Avalos session_pty_cleanup2(Session *s) 234318de8d7fSPeter Avalos { 234418de8d7fSPeter Avalos if (s == NULL) { 234518de8d7fSPeter Avalos error("session_pty_cleanup: no session"); 234618de8d7fSPeter Avalos return; 234718de8d7fSPeter Avalos } 234818de8d7fSPeter Avalos if (s->ttyfd == -1) 234918de8d7fSPeter Avalos return; 235018de8d7fSPeter Avalos 235118de8d7fSPeter Avalos debug("session_pty_cleanup: session %d release %s", s->self, s->tty); 235218de8d7fSPeter Avalos 235318de8d7fSPeter Avalos /* Record that the user has logged out. */ 235418de8d7fSPeter Avalos if (s->pid != 0) 235518de8d7fSPeter Avalos record_logout(s->pid, s->tty, s->pw->pw_name); 235618de8d7fSPeter Avalos 235718de8d7fSPeter Avalos /* Release the pseudo-tty. */ 235818de8d7fSPeter Avalos if (getuid() == 0) 235918de8d7fSPeter Avalos pty_release(s->tty); 236018de8d7fSPeter Avalos 236118de8d7fSPeter Avalos /* 236218de8d7fSPeter Avalos * Close the server side of the socket pairs. We must do this after 236318de8d7fSPeter Avalos * the pty cleanup, so that another process doesn't get this pty 236418de8d7fSPeter Avalos * while we're still cleaning up. 236518de8d7fSPeter Avalos */ 236618de8d7fSPeter Avalos if (s->ptymaster != -1 && close(s->ptymaster) < 0) 236718de8d7fSPeter Avalos error("close(s->ptymaster/%d): %s", 236818de8d7fSPeter Avalos s->ptymaster, strerror(errno)); 236918de8d7fSPeter Avalos 237018de8d7fSPeter Avalos /* unlink pty from session */ 237118de8d7fSPeter Avalos s->ttyfd = -1; 237218de8d7fSPeter Avalos } 237318de8d7fSPeter Avalos 237418de8d7fSPeter Avalos void 237518de8d7fSPeter Avalos session_pty_cleanup(Session *s) 237618de8d7fSPeter Avalos { 237718de8d7fSPeter Avalos PRIVSEP(session_pty_cleanup2(s)); 237818de8d7fSPeter Avalos } 237918de8d7fSPeter Avalos 238018de8d7fSPeter Avalos static char * 238118de8d7fSPeter Avalos sig2name(int sig) 238218de8d7fSPeter Avalos { 238318de8d7fSPeter Avalos #define SSH_SIG(x) if (sig == SIG ## x) return #x 238418de8d7fSPeter Avalos SSH_SIG(ABRT); 238518de8d7fSPeter Avalos SSH_SIG(ALRM); 238618de8d7fSPeter Avalos SSH_SIG(FPE); 238718de8d7fSPeter Avalos SSH_SIG(HUP); 238818de8d7fSPeter Avalos SSH_SIG(ILL); 238918de8d7fSPeter Avalos SSH_SIG(INT); 239018de8d7fSPeter Avalos SSH_SIG(KILL); 239118de8d7fSPeter Avalos SSH_SIG(PIPE); 239218de8d7fSPeter Avalos SSH_SIG(QUIT); 239318de8d7fSPeter Avalos SSH_SIG(SEGV); 239418de8d7fSPeter Avalos SSH_SIG(TERM); 239518de8d7fSPeter Avalos SSH_SIG(USR1); 239618de8d7fSPeter Avalos SSH_SIG(USR2); 239718de8d7fSPeter Avalos #undef SSH_SIG 239818de8d7fSPeter Avalos return "SIG@openssh.com"; 239918de8d7fSPeter Avalos } 240018de8d7fSPeter Avalos 240118de8d7fSPeter Avalos static void 240218de8d7fSPeter Avalos session_close_x11(int id) 240318de8d7fSPeter Avalos { 240418de8d7fSPeter Avalos Channel *c; 240518de8d7fSPeter Avalos 240618de8d7fSPeter Avalos if ((c = channel_by_id(id)) == NULL) { 240718de8d7fSPeter Avalos debug("session_close_x11: x11 channel %d missing", id); 240818de8d7fSPeter Avalos } else { 240918de8d7fSPeter Avalos /* Detach X11 listener */ 241018de8d7fSPeter Avalos debug("session_close_x11: detach x11 channel %d", id); 241118de8d7fSPeter Avalos channel_cancel_cleanup(id); 241218de8d7fSPeter Avalos if (c->ostate != CHAN_OUTPUT_CLOSED) 241318de8d7fSPeter Avalos chan_mark_dead(c); 241418de8d7fSPeter Avalos } 241518de8d7fSPeter Avalos } 241618de8d7fSPeter Avalos 241718de8d7fSPeter Avalos static void 241818de8d7fSPeter Avalos session_close_single_x11(int id, void *arg) 241918de8d7fSPeter Avalos { 242018de8d7fSPeter Avalos Session *s; 242118de8d7fSPeter Avalos u_int i; 242218de8d7fSPeter Avalos 242318de8d7fSPeter Avalos debug3("session_close_single_x11: channel %d", id); 242418de8d7fSPeter Avalos channel_cancel_cleanup(id); 242518de8d7fSPeter Avalos if ((s = session_by_x11_channel(id)) == NULL) 242618de8d7fSPeter Avalos fatal("session_close_single_x11: no x11 channel %d", id); 242718de8d7fSPeter Avalos for (i = 0; s->x11_chanids[i] != -1; i++) { 242818de8d7fSPeter Avalos debug("session_close_single_x11: session %d: " 242918de8d7fSPeter Avalos "closing channel %d", s->self, s->x11_chanids[i]); 243018de8d7fSPeter Avalos /* 243118de8d7fSPeter Avalos * The channel "id" is already closing, but make sure we 243218de8d7fSPeter Avalos * close all of its siblings. 243318de8d7fSPeter Avalos */ 243418de8d7fSPeter Avalos if (s->x11_chanids[i] != id) 243518de8d7fSPeter Avalos session_close_x11(s->x11_chanids[i]); 243618de8d7fSPeter Avalos } 2437*36e94dc5SPeter Avalos free(s->x11_chanids); 243818de8d7fSPeter Avalos s->x11_chanids = NULL; 2439*36e94dc5SPeter Avalos free(s->display); 244018de8d7fSPeter Avalos s->display = NULL; 2441*36e94dc5SPeter Avalos free(s->auth_proto); 244218de8d7fSPeter Avalos s->auth_proto = NULL; 2443*36e94dc5SPeter Avalos free(s->auth_data); 244418de8d7fSPeter Avalos s->auth_data = NULL; 2445*36e94dc5SPeter Avalos free(s->auth_display); 244618de8d7fSPeter Avalos s->auth_display = NULL; 244718de8d7fSPeter Avalos } 244818de8d7fSPeter Avalos 244918de8d7fSPeter Avalos static void 245018de8d7fSPeter Avalos session_exit_message(Session *s, int status) 245118de8d7fSPeter Avalos { 245218de8d7fSPeter Avalos Channel *c; 245318de8d7fSPeter Avalos 245418de8d7fSPeter Avalos if ((c = channel_lookup(s->chanid)) == NULL) 245518de8d7fSPeter Avalos fatal("session_exit_message: session %d: no channel %d", 245618de8d7fSPeter Avalos s->self, s->chanid); 245718de8d7fSPeter Avalos debug("session_exit_message: session %d channel %d pid %ld", 245818de8d7fSPeter Avalos s->self, s->chanid, (long)s->pid); 245918de8d7fSPeter Avalos 246018de8d7fSPeter Avalos if (WIFEXITED(status)) { 246118de8d7fSPeter Avalos channel_request_start(s->chanid, "exit-status", 0); 246218de8d7fSPeter Avalos packet_put_int(WEXITSTATUS(status)); 246318de8d7fSPeter Avalos packet_send(); 246418de8d7fSPeter Avalos } else if (WIFSIGNALED(status)) { 246518de8d7fSPeter Avalos channel_request_start(s->chanid, "exit-signal", 0); 246618de8d7fSPeter Avalos packet_put_cstring(sig2name(WTERMSIG(status))); 246718de8d7fSPeter Avalos #ifdef WCOREDUMP 246818de8d7fSPeter Avalos packet_put_char(WCOREDUMP(status)? 1 : 0); 246918de8d7fSPeter Avalos #else /* WCOREDUMP */ 247018de8d7fSPeter Avalos packet_put_char(0); 247118de8d7fSPeter Avalos #endif /* WCOREDUMP */ 247218de8d7fSPeter Avalos packet_put_cstring(""); 247318de8d7fSPeter Avalos packet_put_cstring(""); 247418de8d7fSPeter Avalos packet_send(); 247518de8d7fSPeter Avalos } else { 247618de8d7fSPeter Avalos /* Some weird exit cause. Just exit. */ 247718de8d7fSPeter Avalos packet_disconnect("wait returned status %04x.", status); 247818de8d7fSPeter Avalos } 247918de8d7fSPeter Avalos 248018de8d7fSPeter Avalos /* disconnect channel */ 248118de8d7fSPeter Avalos debug("session_exit_message: release channel %d", s->chanid); 248218de8d7fSPeter Avalos 248318de8d7fSPeter Avalos /* 248418de8d7fSPeter Avalos * Adjust cleanup callback attachment to send close messages when 248518de8d7fSPeter Avalos * the channel gets EOF. The session will be then be closed 248618de8d7fSPeter Avalos * by session_close_by_channel when the childs close their fds. 248718de8d7fSPeter Avalos */ 248818de8d7fSPeter Avalos channel_register_cleanup(c->self, session_close_by_channel, 1); 248918de8d7fSPeter Avalos 249018de8d7fSPeter Avalos /* 249118de8d7fSPeter Avalos * emulate a write failure with 'chan_write_failed', nobody will be 249218de8d7fSPeter Avalos * interested in data we write. 249318de8d7fSPeter Avalos * Note that we must not call 'chan_read_failed', since there could 249418de8d7fSPeter Avalos * be some more data waiting in the pipe. 249518de8d7fSPeter Avalos */ 249618de8d7fSPeter Avalos if (c->ostate != CHAN_OUTPUT_CLOSED) 249718de8d7fSPeter Avalos chan_write_failed(c); 249818de8d7fSPeter Avalos } 249918de8d7fSPeter Avalos 250018de8d7fSPeter Avalos void 250118de8d7fSPeter Avalos session_close(Session *s) 250218de8d7fSPeter Avalos { 250318de8d7fSPeter Avalos u_int i; 250418de8d7fSPeter Avalos 250518de8d7fSPeter Avalos debug("session_close: session %d pid %ld", s->self, (long)s->pid); 250618de8d7fSPeter Avalos if (s->ttyfd != -1) 250718de8d7fSPeter Avalos session_pty_cleanup(s); 2508*36e94dc5SPeter Avalos free(s->term); 2509*36e94dc5SPeter Avalos free(s->display); 2510*36e94dc5SPeter Avalos free(s->x11_chanids); 2511*36e94dc5SPeter Avalos free(s->auth_display); 2512*36e94dc5SPeter Avalos free(s->auth_data); 2513*36e94dc5SPeter Avalos free(s->auth_proto); 2514*36e94dc5SPeter Avalos free(s->subsys); 251518de8d7fSPeter Avalos if (s->env != NULL) { 251618de8d7fSPeter Avalos for (i = 0; i < s->num_env; i++) { 2517*36e94dc5SPeter Avalos free(s->env[i].name); 2518*36e94dc5SPeter Avalos free(s->env[i].val); 251918de8d7fSPeter Avalos } 2520*36e94dc5SPeter Avalos free(s->env); 252118de8d7fSPeter Avalos } 252218de8d7fSPeter Avalos session_proctitle(s); 252318de8d7fSPeter Avalos session_unused(s->self); 252418de8d7fSPeter Avalos } 252518de8d7fSPeter Avalos 252618de8d7fSPeter Avalos void 252718de8d7fSPeter Avalos session_close_by_pid(pid_t pid, int status) 252818de8d7fSPeter Avalos { 252918de8d7fSPeter Avalos Session *s = session_by_pid(pid); 253018de8d7fSPeter Avalos if (s == NULL) { 253118de8d7fSPeter Avalos debug("session_close_by_pid: no session for pid %ld", 253218de8d7fSPeter Avalos (long)pid); 253318de8d7fSPeter Avalos return; 253418de8d7fSPeter Avalos } 253518de8d7fSPeter Avalos if (s->chanid != -1) 253618de8d7fSPeter Avalos session_exit_message(s, status); 253718de8d7fSPeter Avalos if (s->ttyfd != -1) 253818de8d7fSPeter Avalos session_pty_cleanup(s); 253918de8d7fSPeter Avalos s->pid = 0; 254018de8d7fSPeter Avalos } 254118de8d7fSPeter Avalos 254218de8d7fSPeter Avalos /* 254318de8d7fSPeter Avalos * this is called when a channel dies before 254418de8d7fSPeter Avalos * the session 'child' itself dies 254518de8d7fSPeter Avalos */ 254618de8d7fSPeter Avalos void 254718de8d7fSPeter Avalos session_close_by_channel(int id, void *arg) 254818de8d7fSPeter Avalos { 254918de8d7fSPeter Avalos Session *s = session_by_channel(id); 255018de8d7fSPeter Avalos u_int i; 255118de8d7fSPeter Avalos 255218de8d7fSPeter Avalos if (s == NULL) { 255318de8d7fSPeter Avalos debug("session_close_by_channel: no session for id %d", id); 255418de8d7fSPeter Avalos return; 255518de8d7fSPeter Avalos } 255618de8d7fSPeter Avalos debug("session_close_by_channel: channel %d child %ld", 255718de8d7fSPeter Avalos id, (long)s->pid); 255818de8d7fSPeter Avalos if (s->pid != 0) { 255918de8d7fSPeter Avalos debug("session_close_by_channel: channel %d: has child", id); 256018de8d7fSPeter Avalos /* 256118de8d7fSPeter Avalos * delay detach of session, but release pty, since 256218de8d7fSPeter Avalos * the fd's to the child are already closed 256318de8d7fSPeter Avalos */ 256418de8d7fSPeter Avalos if (s->ttyfd != -1) 256518de8d7fSPeter Avalos session_pty_cleanup(s); 256618de8d7fSPeter Avalos return; 256718de8d7fSPeter Avalos } 256818de8d7fSPeter Avalos /* detach by removing callback */ 256918de8d7fSPeter Avalos channel_cancel_cleanup(s->chanid); 257018de8d7fSPeter Avalos 257118de8d7fSPeter Avalos /* Close any X11 listeners associated with this session */ 257218de8d7fSPeter Avalos if (s->x11_chanids != NULL) { 257318de8d7fSPeter Avalos for (i = 0; s->x11_chanids[i] != -1; i++) { 257418de8d7fSPeter Avalos session_close_x11(s->x11_chanids[i]); 257518de8d7fSPeter Avalos s->x11_chanids[i] = -1; 257618de8d7fSPeter Avalos } 257718de8d7fSPeter Avalos } 257818de8d7fSPeter Avalos 257918de8d7fSPeter Avalos s->chanid = -1; 258018de8d7fSPeter Avalos session_close(s); 258118de8d7fSPeter Avalos } 258218de8d7fSPeter Avalos 258318de8d7fSPeter Avalos void 258418de8d7fSPeter Avalos session_destroy_all(void (*closefunc)(Session *)) 258518de8d7fSPeter Avalos { 258618de8d7fSPeter Avalos int i; 258718de8d7fSPeter Avalos for (i = 0; i < sessions_nalloc; i++) { 258818de8d7fSPeter Avalos Session *s = &sessions[i]; 258918de8d7fSPeter Avalos if (s->used) { 259018de8d7fSPeter Avalos if (closefunc != NULL) 259118de8d7fSPeter Avalos closefunc(s); 259218de8d7fSPeter Avalos else 259318de8d7fSPeter Avalos session_close(s); 259418de8d7fSPeter Avalos } 259518de8d7fSPeter Avalos } 259618de8d7fSPeter Avalos } 259718de8d7fSPeter Avalos 259818de8d7fSPeter Avalos static char * 259918de8d7fSPeter Avalos session_tty_list(void) 260018de8d7fSPeter Avalos { 260118de8d7fSPeter Avalos static char buf[1024]; 260218de8d7fSPeter Avalos int i; 260318de8d7fSPeter Avalos char *cp; 260418de8d7fSPeter Avalos 260518de8d7fSPeter Avalos buf[0] = '\0'; 260618de8d7fSPeter Avalos for (i = 0; i < sessions_nalloc; i++) { 260718de8d7fSPeter Avalos Session *s = &sessions[i]; 260818de8d7fSPeter Avalos if (s->used && s->ttyfd != -1) { 260918de8d7fSPeter Avalos 261018de8d7fSPeter Avalos if (strncmp(s->tty, "/dev/", 5) != 0) { 261118de8d7fSPeter Avalos cp = strrchr(s->tty, '/'); 261218de8d7fSPeter Avalos cp = (cp == NULL) ? s->tty : cp + 1; 261318de8d7fSPeter Avalos } else 261418de8d7fSPeter Avalos cp = s->tty + 5; 261518de8d7fSPeter Avalos 261618de8d7fSPeter Avalos if (buf[0] != '\0') 261718de8d7fSPeter Avalos strlcat(buf, ",", sizeof buf); 261818de8d7fSPeter Avalos strlcat(buf, cp, sizeof buf); 261918de8d7fSPeter Avalos } 262018de8d7fSPeter Avalos } 262118de8d7fSPeter Avalos if (buf[0] == '\0') 262218de8d7fSPeter Avalos strlcpy(buf, "notty", sizeof buf); 262318de8d7fSPeter Avalos return buf; 262418de8d7fSPeter Avalos } 262518de8d7fSPeter Avalos 262618de8d7fSPeter Avalos void 262718de8d7fSPeter Avalos session_proctitle(Session *s) 262818de8d7fSPeter Avalos { 262918de8d7fSPeter Avalos if (s->pw == NULL) 263018de8d7fSPeter Avalos error("no user for session %d", s->self); 263118de8d7fSPeter Avalos else 263218de8d7fSPeter Avalos setproctitle("%s@%s", s->pw->pw_name, session_tty_list()); 263318de8d7fSPeter Avalos } 263418de8d7fSPeter Avalos 263518de8d7fSPeter Avalos int 263618de8d7fSPeter Avalos session_setup_x11fwd(Session *s) 263718de8d7fSPeter Avalos { 263818de8d7fSPeter Avalos struct stat st; 263918de8d7fSPeter Avalos char display[512], auth_display[512]; 2640*36e94dc5SPeter Avalos char hostname[NI_MAXHOST]; 264118de8d7fSPeter Avalos u_int i; 264218de8d7fSPeter Avalos 264318de8d7fSPeter Avalos if (no_x11_forwarding_flag) { 264418de8d7fSPeter Avalos packet_send_debug("X11 forwarding disabled in user configuration file."); 264518de8d7fSPeter Avalos return 0; 264618de8d7fSPeter Avalos } 264718de8d7fSPeter Avalos if (!options.x11_forwarding) { 264818de8d7fSPeter Avalos debug("X11 forwarding disabled in server configuration file."); 264918de8d7fSPeter Avalos return 0; 265018de8d7fSPeter Avalos } 265118de8d7fSPeter Avalos if (!options.xauth_location || 265218de8d7fSPeter Avalos (stat(options.xauth_location, &st) == -1)) { 265318de8d7fSPeter Avalos packet_send_debug("No xauth program; cannot forward with spoofing."); 265418de8d7fSPeter Avalos return 0; 265518de8d7fSPeter Avalos } 265618de8d7fSPeter Avalos if (options.use_login) { 265718de8d7fSPeter Avalos packet_send_debug("X11 forwarding disabled; " 265818de8d7fSPeter Avalos "not compatible with UseLogin=yes."); 265918de8d7fSPeter Avalos return 0; 266018de8d7fSPeter Avalos } 266118de8d7fSPeter Avalos if (s->display != NULL) { 266218de8d7fSPeter Avalos debug("X11 display already set."); 266318de8d7fSPeter Avalos return 0; 266418de8d7fSPeter Avalos } 266518de8d7fSPeter Avalos if (x11_create_display_inet(options.x11_display_offset, 266618de8d7fSPeter Avalos options.x11_use_localhost, s->single_connection, 266718de8d7fSPeter Avalos &s->display_number, &s->x11_chanids) == -1) { 266818de8d7fSPeter Avalos debug("x11_create_display_inet failed."); 266918de8d7fSPeter Avalos return 0; 267018de8d7fSPeter Avalos } 267118de8d7fSPeter Avalos for (i = 0; s->x11_chanids[i] != -1; i++) { 267218de8d7fSPeter Avalos channel_register_cleanup(s->x11_chanids[i], 267318de8d7fSPeter Avalos session_close_single_x11, 0); 267418de8d7fSPeter Avalos } 267518de8d7fSPeter Avalos 267618de8d7fSPeter Avalos /* Set up a suitable value for the DISPLAY variable. */ 267718de8d7fSPeter Avalos if (gethostname(hostname, sizeof(hostname)) < 0) 267818de8d7fSPeter Avalos fatal("gethostname: %.100s", strerror(errno)); 267918de8d7fSPeter Avalos /* 268018de8d7fSPeter Avalos * auth_display must be used as the displayname when the 268118de8d7fSPeter Avalos * authorization entry is added with xauth(1). This will be 268218de8d7fSPeter Avalos * different than the DISPLAY string for localhost displays. 268318de8d7fSPeter Avalos */ 268418de8d7fSPeter Avalos if (options.x11_use_localhost) { 268518de8d7fSPeter Avalos snprintf(display, sizeof display, "localhost:%u.%u", 268618de8d7fSPeter Avalos s->display_number, s->screen); 268718de8d7fSPeter Avalos snprintf(auth_display, sizeof auth_display, "unix:%u.%u", 268818de8d7fSPeter Avalos s->display_number, s->screen); 268918de8d7fSPeter Avalos s->display = xstrdup(display); 269018de8d7fSPeter Avalos s->auth_display = xstrdup(auth_display); 269118de8d7fSPeter Avalos } else { 269218de8d7fSPeter Avalos #ifdef IPADDR_IN_DISPLAY 269318de8d7fSPeter Avalos struct hostent *he; 269418de8d7fSPeter Avalos struct in_addr my_addr; 269518de8d7fSPeter Avalos 269618de8d7fSPeter Avalos he = gethostbyname(hostname); 269718de8d7fSPeter Avalos if (he == NULL) { 269818de8d7fSPeter Avalos error("Can't get IP address for X11 DISPLAY."); 269918de8d7fSPeter Avalos packet_send_debug("Can't get IP address for X11 DISPLAY."); 270018de8d7fSPeter Avalos return 0; 270118de8d7fSPeter Avalos } 270218de8d7fSPeter Avalos memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr)); 270318de8d7fSPeter Avalos snprintf(display, sizeof display, "%.50s:%u.%u", inet_ntoa(my_addr), 270418de8d7fSPeter Avalos s->display_number, s->screen); 270518de8d7fSPeter Avalos #else 270618de8d7fSPeter Avalos snprintf(display, sizeof display, "%.400s:%u.%u", hostname, 270718de8d7fSPeter Avalos s->display_number, s->screen); 270818de8d7fSPeter Avalos #endif 270918de8d7fSPeter Avalos s->display = xstrdup(display); 271018de8d7fSPeter Avalos s->auth_display = xstrdup(display); 271118de8d7fSPeter Avalos } 271218de8d7fSPeter Avalos 271318de8d7fSPeter Avalos return 1; 271418de8d7fSPeter Avalos } 271518de8d7fSPeter Avalos 271618de8d7fSPeter Avalos static void 271718de8d7fSPeter Avalos do_authenticated2(Authctxt *authctxt) 271818de8d7fSPeter Avalos { 271918de8d7fSPeter Avalos server_loop2(authctxt); 272018de8d7fSPeter Avalos } 272118de8d7fSPeter Avalos 272218de8d7fSPeter Avalos void 272318de8d7fSPeter Avalos do_cleanup(Authctxt *authctxt) 272418de8d7fSPeter Avalos { 272518de8d7fSPeter Avalos static int called = 0; 272618de8d7fSPeter Avalos 272718de8d7fSPeter Avalos debug("do_cleanup"); 272818de8d7fSPeter Avalos 272918de8d7fSPeter Avalos /* no cleanup if we're in the child for login shell */ 273018de8d7fSPeter Avalos if (is_child) 273118de8d7fSPeter Avalos return; 273218de8d7fSPeter Avalos 273318de8d7fSPeter Avalos /* avoid double cleanup */ 273418de8d7fSPeter Avalos if (called) 273518de8d7fSPeter Avalos return; 273618de8d7fSPeter Avalos called = 1; 273718de8d7fSPeter Avalos 273818de8d7fSPeter Avalos if (authctxt == NULL) 273918de8d7fSPeter Avalos return; 274018de8d7fSPeter Avalos 274118de8d7fSPeter Avalos #ifdef USE_PAM 274218de8d7fSPeter Avalos if (options.use_pam) { 274318de8d7fSPeter Avalos sshpam_cleanup(); 274418de8d7fSPeter Avalos sshpam_thread_cleanup(); 274518de8d7fSPeter Avalos } 274618de8d7fSPeter Avalos #endif 274718de8d7fSPeter Avalos 274818de8d7fSPeter Avalos if (!authctxt->authenticated) 274918de8d7fSPeter Avalos return; 275018de8d7fSPeter Avalos 275118de8d7fSPeter Avalos #ifdef KRB5 275218de8d7fSPeter Avalos if (options.kerberos_ticket_cleanup && 275318de8d7fSPeter Avalos authctxt->krb5_ctx) 275418de8d7fSPeter Avalos krb5_cleanup_proc(authctxt); 275518de8d7fSPeter Avalos #endif 275618de8d7fSPeter Avalos 275718de8d7fSPeter Avalos #ifdef GSSAPI 275818de8d7fSPeter Avalos if (compat20 && options.gss_cleanup_creds) 275918de8d7fSPeter Avalos ssh_gssapi_cleanup_creds(); 276018de8d7fSPeter Avalos #endif 276118de8d7fSPeter Avalos 276218de8d7fSPeter Avalos /* remove agent socket */ 276318de8d7fSPeter Avalos auth_sock_cleanup_proc(authctxt->pw); 276418de8d7fSPeter Avalos 276518de8d7fSPeter Avalos /* 276618de8d7fSPeter Avalos * Cleanup ptys/utmp only if privsep is disabled, 276718de8d7fSPeter Avalos * or if running in monitor. 276818de8d7fSPeter Avalos */ 276918de8d7fSPeter Avalos if (!use_privsep || mm_is_monitor()) 277018de8d7fSPeter Avalos session_destroy_all(session_pty_cleanup2); 277118de8d7fSPeter Avalos } 2772