1*1323ec57SEd Maste /* $OpenBSD: session.c,v 1.330 2022/02/08 08:59:12 dtucker Exp $ */ 2a04a10f8SKris Kennaway /* 3a04a10f8SKris Kennaway * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4a04a10f8SKris Kennaway * All rights reserved 5c2d3a559SKris Kennaway * 6c2d3a559SKris Kennaway * As far as I am concerned, the code I have written for this software 7c2d3a559SKris Kennaway * can be used freely for any purpose. Any derived versions of this 8c2d3a559SKris Kennaway * software must be clearly marked as such, and if the derived work is 9c2d3a559SKris Kennaway * incompatible with the protocol description in the RFC file, it must be 10c2d3a559SKris Kennaway * called by a name other than "ssh" or "Secure Shell". 11c2d3a559SKris Kennaway * 12a04a10f8SKris Kennaway * SSH2 support by Markus Friedl. 13af12a3e7SDag-Erling Smørgrav * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 14e8aafc91SKris Kennaway * 15c2d3a559SKris Kennaway * Redistribution and use in source and binary forms, with or without 16c2d3a559SKris Kennaway * modification, are permitted provided that the following conditions 17c2d3a559SKris Kennaway * are met: 18c2d3a559SKris Kennaway * 1. Redistributions of source code must retain the above copyright 19c2d3a559SKris Kennaway * notice, this list of conditions and the following disclaimer. 20c2d3a559SKris Kennaway * 2. Redistributions in binary form must reproduce the above copyright 21c2d3a559SKris Kennaway * notice, this list of conditions and the following disclaimer in the 22c2d3a559SKris Kennaway * documentation and/or other materials provided with the distribution. 23c2d3a559SKris Kennaway * 24c2d3a559SKris Kennaway * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25c2d3a559SKris Kennaway * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26c2d3a559SKris Kennaway * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27c2d3a559SKris Kennaway * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 28c2d3a559SKris Kennaway * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 29c2d3a559SKris Kennaway * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30c2d3a559SKris Kennaway * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31c2d3a559SKris Kennaway * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32c2d3a559SKris Kennaway * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33c2d3a559SKris Kennaway * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34a04a10f8SKris Kennaway */ 35a04a10f8SKris Kennaway 36a04a10f8SKris Kennaway #include "includes.h" 37333ee039SDag-Erling Smørgrav __RCSID("$FreeBSD$"); 38a04a10f8SKris Kennaway 39333ee039SDag-Erling Smørgrav #include <sys/types.h> 40333ee039SDag-Erling Smørgrav #ifdef HAVE_SYS_STAT_H 41333ee039SDag-Erling Smørgrav # include <sys/stat.h> 42333ee039SDag-Erling Smørgrav #endif 43333ee039SDag-Erling Smørgrav #include <sys/socket.h> 44333ee039SDag-Erling Smørgrav #include <sys/un.h> 45333ee039SDag-Erling Smørgrav #include <sys/wait.h> 46333ee039SDag-Erling Smørgrav 47333ee039SDag-Erling Smørgrav #include <arpa/inet.h> 48333ee039SDag-Erling Smørgrav 49acc1a9efSDag-Erling Smørgrav #include <ctype.h> 50333ee039SDag-Erling Smørgrav #include <errno.h> 51e2f6069cSDag-Erling Smørgrav #include <fcntl.h> 52333ee039SDag-Erling Smørgrav #include <grp.h> 53a0ee8cc6SDag-Erling Smørgrav #include <netdb.h> 54333ee039SDag-Erling Smørgrav #ifdef HAVE_PATHS_H 55333ee039SDag-Erling Smørgrav #include <paths.h> 56333ee039SDag-Erling Smørgrav #endif 57333ee039SDag-Erling Smørgrav #include <pwd.h> 58333ee039SDag-Erling Smørgrav #include <signal.h> 59333ee039SDag-Erling Smørgrav #include <stdio.h> 60333ee039SDag-Erling Smørgrav #include <stdlib.h> 61333ee039SDag-Erling Smørgrav #include <string.h> 6219261079SEd Maste #include <stdarg.h> 63333ee039SDag-Erling Smørgrav #include <unistd.h> 64bc5531deSDag-Erling Smørgrav #include <limits.h> 65333ee039SDag-Erling Smørgrav 66d4af9e69SDag-Erling Smørgrav #include "openbsd-compat/sys-queue.h" 67333ee039SDag-Erling Smørgrav #include "xmalloc.h" 68a04a10f8SKris Kennaway #include "ssh.h" 69ca3176e7SBrian Feldman #include "ssh2.h" 70ca3176e7SBrian Feldman #include "sshpty.h" 71a04a10f8SKris Kennaway #include "packet.h" 72190cef3dSDag-Erling Smørgrav #include "sshbuf.h" 73190cef3dSDag-Erling Smørgrav #include "ssherr.h" 7421e764dfSDag-Erling Smørgrav #include "match.h" 75a04a10f8SKris Kennaway #include "uidswap.h" 76a04a10f8SKris Kennaway #include "compat.h" 77a04a10f8SKris Kennaway #include "channels.h" 78190cef3dSDag-Erling Smørgrav #include "sshkey.h" 79333ee039SDag-Erling Smørgrav #include "cipher.h" 80333ee039SDag-Erling Smørgrav #ifdef GSSAPI 81333ee039SDag-Erling Smørgrav #include "ssh-gss.h" 82333ee039SDag-Erling Smørgrav #endif 83333ee039SDag-Erling Smørgrav #include "hostfile.h" 84a04a10f8SKris Kennaway #include "auth.h" 85c2d3a559SKris Kennaway #include "auth-options.h" 86e4a9863fSDag-Erling Smørgrav #include "authfd.h" 87ca3176e7SBrian Feldman #include "pathnames.h" 88ca3176e7SBrian Feldman #include "log.h" 89a0ee8cc6SDag-Erling Smørgrav #include "misc.h" 90ca3176e7SBrian Feldman #include "servconf.h" 91ca3176e7SBrian Feldman #include "sshlogin.h" 92ca3176e7SBrian Feldman #include "serverloop.h" 93ca3176e7SBrian Feldman #include "canohost.h" 94ca3176e7SBrian Feldman #include "session.h" 95d4ecd108SDag-Erling Smørgrav #include "kex.h" 9680628bacSDag-Erling Smørgrav #include "monitor_wrap.h" 97d4af9e69SDag-Erling Smørgrav #include "sftp.h" 984f52dfbbSDag-Erling Smørgrav #include "atomicio.h" 99a04a10f8SKris Kennaway 1001ec0d754SDag-Erling Smørgrav #if defined(KRB5) && defined(USE_AFS) 1011ec0d754SDag-Erling Smørgrav #include <kafs.h> 1021ec0d754SDag-Erling Smørgrav #endif 1031ec0d754SDag-Erling Smørgrav 104e146993eSDag-Erling Smørgrav #ifdef WITH_SELINUX 105e146993eSDag-Erling Smørgrav #include <selinux/selinux.h> 106e146993eSDag-Erling Smørgrav #endif 107e146993eSDag-Erling Smørgrav 108cce7d346SDag-Erling Smørgrav #define IS_INTERNAL_SFTP(c) \ 109cce7d346SDag-Erling Smørgrav (!strncmp(c, INTERNAL_SFTP_NAME, sizeof(INTERNAL_SFTP_NAME) - 1) && \ 110cce7d346SDag-Erling Smørgrav (c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\0' || \ 111cce7d346SDag-Erling Smørgrav c[sizeof(INTERNAL_SFTP_NAME) - 1] == ' ' || \ 112cce7d346SDag-Erling Smørgrav c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\t')) 113cce7d346SDag-Erling Smørgrav 114a04a10f8SKris Kennaway /* func */ 115a04a10f8SKris Kennaway 116a04a10f8SKris Kennaway Session *session_new(void); 1174f52dfbbSDag-Erling Smørgrav void session_set_fds(struct ssh *, Session *, int, int, int, int, int); 1181ec0d754SDag-Erling Smørgrav void session_pty_cleanup(Session *); 119af12a3e7SDag-Erling Smørgrav void session_proctitle(Session *); 1204f52dfbbSDag-Erling Smørgrav int session_setup_x11fwd(struct ssh *, Session *); 1214f52dfbbSDag-Erling Smørgrav int do_exec_pty(struct ssh *, Session *, const char *); 1224f52dfbbSDag-Erling Smørgrav int do_exec_no_pty(struct ssh *, Session *, const char *); 1234f52dfbbSDag-Erling Smørgrav int do_exec(struct ssh *, Session *, const char *); 1244f52dfbbSDag-Erling Smørgrav void do_login(struct ssh *, Session *, const char *); 1254f52dfbbSDag-Erling Smørgrav void do_child(struct ssh *, Session *, const char *); 126ca3176e7SBrian Feldman void do_motd(void); 127af12a3e7SDag-Erling Smørgrav int check_quietlogin(Session *, const char *); 128a04a10f8SKris Kennaway 1294f52dfbbSDag-Erling Smørgrav static void do_authenticated2(struct ssh *, Authctxt *); 130af12a3e7SDag-Erling Smørgrav 1314f52dfbbSDag-Erling Smørgrav static int session_pty_req(struct ssh *, Session *); 132a04a10f8SKris Kennaway 133a04a10f8SKris Kennaway /* import */ 134a04a10f8SKris Kennaway extern ServerOptions options; 135a04a10f8SKris Kennaway extern char *__progname; 136a04a10f8SKris Kennaway extern int debug_flag; 137ca3176e7SBrian Feldman extern u_int utmp_len; 138c2d3a559SKris Kennaway extern int startup_pipe; 139ca3176e7SBrian Feldman extern void destroy_sensitive_data(void); 140190cef3dSDag-Erling Smørgrav extern struct sshbuf *loginmsg; 14147dd1d1bSDag-Erling Smørgrav extern struct sshauthopt *auth_opts; 1426d0d51a4SKyle Evans extern char *tun_fwd_ifnames; /* serverloop.c */ 143a04a10f8SKris Kennaway 144c2d3a559SKris Kennaway /* original command from peer. */ 145af12a3e7SDag-Erling Smørgrav const char *original_command = NULL; 146c2d3a559SKris Kennaway 147a04a10f8SKris Kennaway /* data */ 148d4af9e69SDag-Erling Smørgrav static int sessions_first_unused = -1; 149d4af9e69SDag-Erling Smørgrav static int sessions_nalloc = 0; 150d4af9e69SDag-Erling Smørgrav static Session *sessions = NULL; 151d4af9e69SDag-Erling Smørgrav 152d4af9e69SDag-Erling Smørgrav #define SUBSYSTEM_NONE 0 153d4af9e69SDag-Erling Smørgrav #define SUBSYSTEM_EXT 1 154d4af9e69SDag-Erling Smørgrav #define SUBSYSTEM_INT_SFTP 2 155b15c8340SDag-Erling Smørgrav #define SUBSYSTEM_INT_SFTP_ERROR 3 156a04a10f8SKris Kennaway 157c2d3a559SKris Kennaway #ifdef HAVE_LOGIN_CAP 15880628bacSDag-Erling Smørgrav login_cap_t *lc; 159c2d3a559SKris Kennaway #endif 160a04a10f8SKris Kennaway 1611ec0d754SDag-Erling Smørgrav static int is_child = 0; 162acc1a9efSDag-Erling Smørgrav static int in_chroot = 0; 1631ec0d754SDag-Erling Smørgrav 1644f52dfbbSDag-Erling Smørgrav /* File containing userauth info, if ExposeAuthInfo set */ 1654f52dfbbSDag-Erling Smørgrav static char *auth_info_file = NULL; 1664f52dfbbSDag-Erling Smørgrav 16780628bacSDag-Erling Smørgrav /* Name and directory of socket for authentication agent forwarding. */ 16880628bacSDag-Erling Smørgrav static char *auth_sock_name = NULL; 16980628bacSDag-Erling Smørgrav static char *auth_sock_dir = NULL; 17080628bacSDag-Erling Smørgrav 17180628bacSDag-Erling Smørgrav /* removes the agent forwarding socket */ 17280628bacSDag-Erling Smørgrav 17380628bacSDag-Erling Smørgrav static void 1741ec0d754SDag-Erling Smørgrav auth_sock_cleanup_proc(struct passwd *pw) 17580628bacSDag-Erling Smørgrav { 17680628bacSDag-Erling Smørgrav if (auth_sock_name != NULL) { 17780628bacSDag-Erling Smørgrav temporarily_use_uid(pw); 17880628bacSDag-Erling Smørgrav unlink(auth_sock_name); 17980628bacSDag-Erling Smørgrav rmdir(auth_sock_dir); 18080628bacSDag-Erling Smørgrav auth_sock_name = NULL; 18180628bacSDag-Erling Smørgrav restore_uid(); 18280628bacSDag-Erling Smørgrav } 18380628bacSDag-Erling Smørgrav } 18480628bacSDag-Erling Smørgrav 18580628bacSDag-Erling Smørgrav static int 1864f52dfbbSDag-Erling Smørgrav auth_input_request_forwarding(struct ssh *ssh, struct passwd * pw) 18780628bacSDag-Erling Smørgrav { 18880628bacSDag-Erling Smørgrav Channel *nc; 189d4af9e69SDag-Erling Smørgrav int sock = -1; 19080628bacSDag-Erling Smørgrav 19180628bacSDag-Erling Smørgrav if (auth_sock_name != NULL) { 19280628bacSDag-Erling Smørgrav error("authentication forwarding requested twice."); 19380628bacSDag-Erling Smørgrav return 0; 19480628bacSDag-Erling Smørgrav } 19580628bacSDag-Erling Smørgrav 19680628bacSDag-Erling Smørgrav /* Temporarily drop privileged uid for mkdir/bind. */ 19780628bacSDag-Erling Smørgrav temporarily_use_uid(pw); 19880628bacSDag-Erling Smørgrav 19980628bacSDag-Erling Smørgrav /* Allocate a buffer for the socket name, and format the name. */ 200d4af9e69SDag-Erling Smørgrav auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX"); 20180628bacSDag-Erling Smørgrav 20280628bacSDag-Erling Smørgrav /* Create private directory for socket */ 20380628bacSDag-Erling Smørgrav if (mkdtemp(auth_sock_dir) == NULL) { 20419261079SEd Maste ssh_packet_send_debug(ssh, "Agent forwarding disabled: " 20580628bacSDag-Erling Smørgrav "mkdtemp() failed: %.100s", strerror(errno)); 20680628bacSDag-Erling Smørgrav restore_uid(); 207e4a9863fSDag-Erling Smørgrav free(auth_sock_dir); 20880628bacSDag-Erling Smørgrav auth_sock_dir = NULL; 209d4af9e69SDag-Erling Smørgrav goto authsock_err; 21080628bacSDag-Erling Smørgrav } 211d4af9e69SDag-Erling Smørgrav 212d4af9e69SDag-Erling Smørgrav xasprintf(&auth_sock_name, "%s/agent.%ld", 21380628bacSDag-Erling Smørgrav auth_sock_dir, (long) getpid()); 21480628bacSDag-Erling Smørgrav 215a0ee8cc6SDag-Erling Smørgrav /* Start a Unix listener on auth_sock_name. */ 216a0ee8cc6SDag-Erling Smørgrav sock = unix_listener(auth_sock_name, SSH_LISTEN_BACKLOG, 0); 21780628bacSDag-Erling Smørgrav 21880628bacSDag-Erling Smørgrav /* Restore the privileged uid. */ 21980628bacSDag-Erling Smørgrav restore_uid(); 22080628bacSDag-Erling Smørgrav 221a0ee8cc6SDag-Erling Smørgrav /* Check for socket/bind/listen failure. */ 222a0ee8cc6SDag-Erling Smørgrav if (sock < 0) 223d4af9e69SDag-Erling Smørgrav goto authsock_err; 22480628bacSDag-Erling Smørgrav 22560c59fadSDag-Erling Smørgrav /* Allocate a channel for the authentication agent socket. */ 2264f52dfbbSDag-Erling Smørgrav nc = channel_new(ssh, "auth socket", 22780628bacSDag-Erling Smørgrav SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, 22880628bacSDag-Erling Smørgrav CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 229cf2b5f3bSDag-Erling Smørgrav 0, "auth socket", 1); 230cce7d346SDag-Erling Smørgrav nc->path = xstrdup(auth_sock_name); 23180628bacSDag-Erling Smørgrav return 1; 232d4af9e69SDag-Erling Smørgrav 233d4af9e69SDag-Erling Smørgrav authsock_err: 234e4a9863fSDag-Erling Smørgrav free(auth_sock_name); 235d4af9e69SDag-Erling Smørgrav if (auth_sock_dir != NULL) { 23619261079SEd Maste temporarily_use_uid(pw); 237d4af9e69SDag-Erling Smørgrav rmdir(auth_sock_dir); 23819261079SEd Maste restore_uid(); 239e4a9863fSDag-Erling Smørgrav free(auth_sock_dir); 240d4af9e69SDag-Erling Smørgrav } 241d4af9e69SDag-Erling Smørgrav if (sock != -1) 242d4af9e69SDag-Erling Smørgrav close(sock); 243d4af9e69SDag-Erling Smørgrav auth_sock_name = NULL; 244d4af9e69SDag-Erling Smørgrav auth_sock_dir = NULL; 245d4af9e69SDag-Erling Smørgrav return 0; 24680628bacSDag-Erling Smørgrav } 24780628bacSDag-Erling Smørgrav 2481ec0d754SDag-Erling Smørgrav static void 2491ec0d754SDag-Erling Smørgrav display_loginmsg(void) 2501ec0d754SDag-Erling Smørgrav { 251190cef3dSDag-Erling Smørgrav int r; 252190cef3dSDag-Erling Smørgrav 253190cef3dSDag-Erling Smørgrav if (sshbuf_len(loginmsg) == 0) 254190cef3dSDag-Erling Smørgrav return; 255190cef3dSDag-Erling Smørgrav if ((r = sshbuf_put_u8(loginmsg, 0)) != 0) 25619261079SEd Maste fatal_fr(r, "sshbuf_put_u8"); 257190cef3dSDag-Erling Smørgrav printf("%s", (char *)sshbuf_ptr(loginmsg)); 258190cef3dSDag-Erling Smørgrav sshbuf_reset(loginmsg); 2591ec0d754SDag-Erling Smørgrav } 26080628bacSDag-Erling Smørgrav 2614f52dfbbSDag-Erling Smørgrav static void 2624f52dfbbSDag-Erling Smørgrav prepare_auth_info_file(struct passwd *pw, struct sshbuf *info) 2634f52dfbbSDag-Erling Smørgrav { 2644f52dfbbSDag-Erling Smørgrav int fd = -1, success = 0; 2654f52dfbbSDag-Erling Smørgrav 2664f52dfbbSDag-Erling Smørgrav if (!options.expose_userauth_info || info == NULL) 2674f52dfbbSDag-Erling Smørgrav return; 2684f52dfbbSDag-Erling Smørgrav 2694f52dfbbSDag-Erling Smørgrav temporarily_use_uid(pw); 2704f52dfbbSDag-Erling Smørgrav auth_info_file = xstrdup("/tmp/sshauth.XXXXXXXXXXXXXXX"); 2714f52dfbbSDag-Erling Smørgrav if ((fd = mkstemp(auth_info_file)) == -1) { 27219261079SEd Maste error_f("mkstemp: %s", strerror(errno)); 2734f52dfbbSDag-Erling Smørgrav goto out; 2744f52dfbbSDag-Erling Smørgrav } 2754f52dfbbSDag-Erling Smørgrav if (atomicio(vwrite, fd, sshbuf_mutable_ptr(info), 2764f52dfbbSDag-Erling Smørgrav sshbuf_len(info)) != sshbuf_len(info)) { 27719261079SEd Maste error_f("write: %s", strerror(errno)); 2784f52dfbbSDag-Erling Smørgrav goto out; 2794f52dfbbSDag-Erling Smørgrav } 2804f52dfbbSDag-Erling Smørgrav if (close(fd) != 0) { 28119261079SEd Maste error_f("close: %s", strerror(errno)); 2824f52dfbbSDag-Erling Smørgrav goto out; 2834f52dfbbSDag-Erling Smørgrav } 2844f52dfbbSDag-Erling Smørgrav success = 1; 2854f52dfbbSDag-Erling Smørgrav out: 2864f52dfbbSDag-Erling Smørgrav if (!success) { 2874f52dfbbSDag-Erling Smørgrav if (fd != -1) 2884f52dfbbSDag-Erling Smørgrav close(fd); 2894f52dfbbSDag-Erling Smørgrav free(auth_info_file); 2904f52dfbbSDag-Erling Smørgrav auth_info_file = NULL; 2914f52dfbbSDag-Erling Smørgrav } 2924f52dfbbSDag-Erling Smørgrav restore_uid(); 2934f52dfbbSDag-Erling Smørgrav } 2944f52dfbbSDag-Erling Smørgrav 29547dd1d1bSDag-Erling Smørgrav static void 296190cef3dSDag-Erling Smørgrav set_fwdpermit_from_authopts(struct ssh *ssh, const struct sshauthopt *opts) 29747dd1d1bSDag-Erling Smørgrav { 29847dd1d1bSDag-Erling Smørgrav char *tmp, *cp, *host; 29947dd1d1bSDag-Erling Smørgrav int port; 30047dd1d1bSDag-Erling Smørgrav size_t i; 30147dd1d1bSDag-Erling Smørgrav 302190cef3dSDag-Erling Smørgrav if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0) { 303190cef3dSDag-Erling Smørgrav channel_clear_permission(ssh, FORWARD_USER, FORWARD_LOCAL); 30447dd1d1bSDag-Erling Smørgrav for (i = 0; i < auth_opts->npermitopen; i++) { 30547dd1d1bSDag-Erling Smørgrav tmp = cp = xstrdup(auth_opts->permitopen[i]); 30647dd1d1bSDag-Erling Smørgrav /* This shouldn't fail as it has already been checked */ 307*1323ec57SEd Maste if ((host = hpdelim2(&cp, NULL)) == NULL) 30819261079SEd Maste fatal_f("internal error: hpdelim"); 30947dd1d1bSDag-Erling Smørgrav host = cleanhostname(host); 31047dd1d1bSDag-Erling Smørgrav if (cp == NULL || (port = permitopen_port(cp)) < 0) 31119261079SEd Maste fatal_f("internal error: permitopen port"); 312190cef3dSDag-Erling Smørgrav channel_add_permission(ssh, 313190cef3dSDag-Erling Smørgrav FORWARD_USER, FORWARD_LOCAL, host, port); 31447dd1d1bSDag-Erling Smørgrav free(tmp); 31547dd1d1bSDag-Erling Smørgrav } 31647dd1d1bSDag-Erling Smørgrav } 317190cef3dSDag-Erling Smørgrav if ((options.allow_tcp_forwarding & FORWARD_REMOTE) != 0) { 318190cef3dSDag-Erling Smørgrav channel_clear_permission(ssh, FORWARD_USER, FORWARD_REMOTE); 319190cef3dSDag-Erling Smørgrav for (i = 0; i < auth_opts->npermitlisten; i++) { 320190cef3dSDag-Erling Smørgrav tmp = cp = xstrdup(auth_opts->permitlisten[i]); 321190cef3dSDag-Erling Smørgrav /* This shouldn't fail as it has already been checked */ 322190cef3dSDag-Erling Smørgrav if ((host = hpdelim(&cp)) == NULL) 32319261079SEd Maste fatal_f("internal error: hpdelim"); 324190cef3dSDag-Erling Smørgrav host = cleanhostname(host); 325190cef3dSDag-Erling Smørgrav if (cp == NULL || (port = permitopen_port(cp)) < 0) 32619261079SEd Maste fatal_f("internal error: permitlisten port"); 327190cef3dSDag-Erling Smørgrav channel_add_permission(ssh, 328190cef3dSDag-Erling Smørgrav FORWARD_USER, FORWARD_REMOTE, host, port); 329190cef3dSDag-Erling Smørgrav free(tmp); 330190cef3dSDag-Erling Smørgrav } 331190cef3dSDag-Erling Smørgrav } 332190cef3dSDag-Erling Smørgrav } 33347dd1d1bSDag-Erling Smørgrav 334ca3176e7SBrian Feldman void 3354f52dfbbSDag-Erling Smørgrav do_authenticated(struct ssh *ssh, Authctxt *authctxt) 336ca3176e7SBrian Feldman { 337e73e9afaSDag-Erling Smørgrav setproctitle("%s", authctxt->pw->pw_name); 338e73e9afaSDag-Erling Smørgrav 33947dd1d1bSDag-Erling Smørgrav auth_log_authopts("active", auth_opts, 0); 34047dd1d1bSDag-Erling Smørgrav 341ca3176e7SBrian Feldman /* setup the channel layer */ 342a0ee8cc6SDag-Erling Smørgrav /* XXX - streamlocal? */ 343190cef3dSDag-Erling Smørgrav set_fwdpermit_from_authopts(ssh, auth_opts); 344ca3176e7SBrian Feldman 345190cef3dSDag-Erling Smørgrav if (!auth_opts->permit_port_forwarding_flag || 346190cef3dSDag-Erling Smørgrav options.disable_forwarding) { 347190cef3dSDag-Erling Smørgrav channel_disable_admin(ssh, FORWARD_LOCAL); 348190cef3dSDag-Erling Smørgrav channel_disable_admin(ssh, FORWARD_REMOTE); 349190cef3dSDag-Erling Smørgrav } else { 350190cef3dSDag-Erling Smørgrav if ((options.allow_tcp_forwarding & FORWARD_LOCAL) == 0) 351190cef3dSDag-Erling Smørgrav channel_disable_admin(ssh, FORWARD_LOCAL); 352190cef3dSDag-Erling Smørgrav else 353190cef3dSDag-Erling Smørgrav channel_permit_all(ssh, FORWARD_LOCAL); 354190cef3dSDag-Erling Smørgrav if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0) 355190cef3dSDag-Erling Smørgrav channel_disable_admin(ssh, FORWARD_REMOTE); 356190cef3dSDag-Erling Smørgrav else 357190cef3dSDag-Erling Smørgrav channel_permit_all(ssh, FORWARD_REMOTE); 358190cef3dSDag-Erling Smørgrav } 35919261079SEd Maste auth_debug_send(ssh); 360b15c8340SDag-Erling Smørgrav 3614f52dfbbSDag-Erling Smørgrav prepare_auth_info_file(authctxt->pw, authctxt->session_info); 3624f52dfbbSDag-Erling Smørgrav 3634f52dfbbSDag-Erling Smørgrav do_authenticated2(ssh, authctxt); 3644f52dfbbSDag-Erling Smørgrav 3654f52dfbbSDag-Erling Smørgrav do_cleanup(ssh, authctxt); 366a04a10f8SKris Kennaway } 367a04a10f8SKris Kennaway 368acc1a9efSDag-Erling Smørgrav /* Check untrusted xauth strings for metacharacters */ 369acc1a9efSDag-Erling Smørgrav static int 370acc1a9efSDag-Erling Smørgrav xauth_valid_string(const char *s) 371acc1a9efSDag-Erling Smørgrav { 372acc1a9efSDag-Erling Smørgrav size_t i; 373acc1a9efSDag-Erling Smørgrav 374acc1a9efSDag-Erling Smørgrav for (i = 0; s[i] != '\0'; i++) { 375acc1a9efSDag-Erling Smørgrav if (!isalnum((u_char)s[i]) && 376acc1a9efSDag-Erling Smørgrav s[i] != '.' && s[i] != ':' && s[i] != '/' && 377acc1a9efSDag-Erling Smørgrav s[i] != '-' && s[i] != '_') 378acc1a9efSDag-Erling Smørgrav return 0; 379acc1a9efSDag-Erling Smørgrav } 380acc1a9efSDag-Erling Smørgrav return 1; 381acc1a9efSDag-Erling Smørgrav } 382acc1a9efSDag-Erling Smørgrav 383f7167e0eSDag-Erling Smørgrav #define USE_PIPES 1 384a04a10f8SKris Kennaway /* 385a04a10f8SKris Kennaway * This is called to fork and execute a command when we have no tty. This 386a04a10f8SKris Kennaway * will call do_child from the child, and server_loop from the parent after 387a04a10f8SKris Kennaway * setting up file descriptors and such. 388a04a10f8SKris Kennaway */ 389d4af9e69SDag-Erling Smørgrav int 3904f52dfbbSDag-Erling Smørgrav do_exec_no_pty(struct ssh *ssh, Session *s, const char *command) 391a04a10f8SKris Kennaway { 39280628bacSDag-Erling Smørgrav pid_t pid; 393a04a10f8SKris Kennaway #ifdef USE_PIPES 394a04a10f8SKris Kennaway int pin[2], pout[2], perr[2]; 395d4af9e69SDag-Erling Smørgrav 396e2f6069cSDag-Erling Smørgrav if (s == NULL) 397e2f6069cSDag-Erling Smørgrav fatal("do_exec_no_pty: no session"); 398e2f6069cSDag-Erling Smørgrav 399a04a10f8SKris Kennaway /* Allocate pipes for communicating with the program. */ 40019261079SEd Maste if (pipe(pin) == -1) { 40119261079SEd Maste error_f("pipe in: %.100s", strerror(errno)); 402d4af9e69SDag-Erling Smørgrav return -1; 403d4af9e69SDag-Erling Smørgrav } 40419261079SEd Maste if (pipe(pout) == -1) { 40519261079SEd Maste error_f("pipe out: %.100s", strerror(errno)); 406d4af9e69SDag-Erling Smørgrav close(pin[0]); 407d4af9e69SDag-Erling Smørgrav close(pin[1]); 408d4af9e69SDag-Erling Smørgrav return -1; 409d4af9e69SDag-Erling Smørgrav } 41019261079SEd Maste if (pipe(perr) == -1) { 41119261079SEd Maste error_f("pipe err: %.100s", strerror(errno)); 412d4af9e69SDag-Erling Smørgrav close(pin[0]); 413d4af9e69SDag-Erling Smørgrav close(pin[1]); 414d4af9e69SDag-Erling Smørgrav close(pout[0]); 415d4af9e69SDag-Erling Smørgrav close(pout[1]); 416d4af9e69SDag-Erling Smørgrav return -1; 417d4af9e69SDag-Erling Smørgrav } 418d4af9e69SDag-Erling Smørgrav #else 419a04a10f8SKris Kennaway int inout[2], err[2]; 420d4af9e69SDag-Erling Smørgrav 421e2f6069cSDag-Erling Smørgrav if (s == NULL) 422e2f6069cSDag-Erling Smørgrav fatal("do_exec_no_pty: no session"); 423e2f6069cSDag-Erling Smørgrav 424a04a10f8SKris Kennaway /* Uses socket pairs to communicate with the program. */ 42519261079SEd Maste if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) { 42619261079SEd Maste error_f("socketpair #1: %.100s", strerror(errno)); 427d4af9e69SDag-Erling Smørgrav return -1; 428d4af9e69SDag-Erling Smørgrav } 42919261079SEd Maste if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) == -1) { 43019261079SEd Maste error_f("socketpair #2: %.100s", strerror(errno)); 431d4af9e69SDag-Erling Smørgrav close(inout[0]); 432d4af9e69SDag-Erling Smørgrav close(inout[1]); 433d4af9e69SDag-Erling Smørgrav return -1; 434d4af9e69SDag-Erling Smørgrav } 435d4af9e69SDag-Erling Smørgrav #endif 436d4af9e69SDag-Erling Smørgrav 437a04a10f8SKris Kennaway session_proctitle(s); 438a04a10f8SKris Kennaway 439a04a10f8SKris Kennaway /* Fork the child. */ 440d4af9e69SDag-Erling Smørgrav switch ((pid = fork())) { 441d4af9e69SDag-Erling Smørgrav case -1: 44219261079SEd Maste error_f("fork: %.100s", strerror(errno)); 443d4af9e69SDag-Erling Smørgrav #ifdef USE_PIPES 444d4af9e69SDag-Erling Smørgrav close(pin[0]); 445d4af9e69SDag-Erling Smørgrav close(pin[1]); 446d4af9e69SDag-Erling Smørgrav close(pout[0]); 447d4af9e69SDag-Erling Smørgrav close(pout[1]); 448d4af9e69SDag-Erling Smørgrav close(perr[0]); 449d4af9e69SDag-Erling Smørgrav close(perr[1]); 450d4af9e69SDag-Erling Smørgrav #else 451d4af9e69SDag-Erling Smørgrav close(inout[0]); 452d4af9e69SDag-Erling Smørgrav close(inout[1]); 453d4af9e69SDag-Erling Smørgrav close(err[0]); 454d4af9e69SDag-Erling Smørgrav close(err[1]); 455d4af9e69SDag-Erling Smørgrav #endif 456d4af9e69SDag-Erling Smørgrav return -1; 457d4af9e69SDag-Erling Smørgrav case 0: 4581ec0d754SDag-Erling Smørgrav is_child = 1; 459f388f5efSDag-Erling Smørgrav 460a04a10f8SKris Kennaway /* 461a04a10f8SKris Kennaway * Create a new session and process group since the 4.4BSD 462a04a10f8SKris Kennaway * setlogin() affects the entire process group. 463a04a10f8SKris Kennaway */ 46419261079SEd Maste if (setsid() == -1) 465a04a10f8SKris Kennaway error("setsid failed: %.100s", strerror(errno)); 466a04a10f8SKris Kennaway 467a04a10f8SKris Kennaway #ifdef USE_PIPES 468a04a10f8SKris Kennaway /* 469a04a10f8SKris Kennaway * Redirect stdin. We close the parent side of the socket 470a04a10f8SKris Kennaway * pair, and make the child side the standard input. 471a04a10f8SKris Kennaway */ 472a04a10f8SKris Kennaway close(pin[1]); 47319261079SEd Maste if (dup2(pin[0], 0) == -1) 474a04a10f8SKris Kennaway perror("dup2 stdin"); 475a04a10f8SKris Kennaway close(pin[0]); 476a04a10f8SKris Kennaway 477a04a10f8SKris Kennaway /* Redirect stdout. */ 478a04a10f8SKris Kennaway close(pout[0]); 47919261079SEd Maste if (dup2(pout[1], 1) == -1) 480a04a10f8SKris Kennaway perror("dup2 stdout"); 481a04a10f8SKris Kennaway close(pout[1]); 482a04a10f8SKris Kennaway 483a04a10f8SKris Kennaway /* Redirect stderr. */ 484a04a10f8SKris Kennaway close(perr[0]); 48519261079SEd Maste if (dup2(perr[1], 2) == -1) 486a04a10f8SKris Kennaway perror("dup2 stderr"); 487a04a10f8SKris Kennaway close(perr[1]); 488d4af9e69SDag-Erling Smørgrav #else 489a04a10f8SKris Kennaway /* 490a04a10f8SKris Kennaway * Redirect stdin, stdout, and stderr. Stdin and stdout will 491a04a10f8SKris Kennaway * use the same socket, as some programs (particularly rdist) 492a04a10f8SKris Kennaway * seem to depend on it. 493a04a10f8SKris Kennaway */ 494a04a10f8SKris Kennaway close(inout[1]); 495a04a10f8SKris Kennaway close(err[1]); 49619261079SEd Maste if (dup2(inout[0], 0) == -1) /* stdin */ 497a04a10f8SKris Kennaway perror("dup2 stdin"); 49819261079SEd Maste if (dup2(inout[0], 1) == -1) /* stdout (same as stdin) */ 499a04a10f8SKris Kennaway perror("dup2 stdout"); 500d4af9e69SDag-Erling Smørgrav close(inout[0]); 50119261079SEd Maste if (dup2(err[0], 2) == -1) /* stderr */ 502a04a10f8SKris Kennaway perror("dup2 stderr"); 503d4af9e69SDag-Erling Smørgrav close(err[0]); 504d4af9e69SDag-Erling Smørgrav #endif 505d4af9e69SDag-Erling Smørgrav 506a04a10f8SKris Kennaway /* Do processing for the child (exec command etc). */ 5074f52dfbbSDag-Erling Smørgrav do_child(ssh, s, command); 508a04a10f8SKris Kennaway /* NOTREACHED */ 509d4af9e69SDag-Erling Smørgrav default: 510d4af9e69SDag-Erling Smørgrav break; 511a04a10f8SKris Kennaway } 512d4af9e69SDag-Erling Smørgrav 513989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN 514989dd127SDag-Erling Smørgrav cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); 515989dd127SDag-Erling Smørgrav #endif 516d4af9e69SDag-Erling Smørgrav 517a04a10f8SKris Kennaway s->pid = pid; 518ca3176e7SBrian Feldman /* Set interactive/non-interactive mode. */ 51919261079SEd Maste ssh_packet_set_interactive(ssh, s->display != NULL, 5204a421b63SDag-Erling Smørgrav options.ip_qos_interactive, options.ip_qos_bulk); 521d4af9e69SDag-Erling Smørgrav 522d4af9e69SDag-Erling Smørgrav /* 523d4af9e69SDag-Erling Smørgrav * Clear loginmsg, since it's the child's responsibility to display 524d4af9e69SDag-Erling Smørgrav * it to the user, otherwise multiple sessions may accumulate 525d4af9e69SDag-Erling Smørgrav * multiple copies of the login messages. 526d4af9e69SDag-Erling Smørgrav */ 527190cef3dSDag-Erling Smørgrav sshbuf_reset(loginmsg); 528d4af9e69SDag-Erling Smørgrav 529a04a10f8SKris Kennaway #ifdef USE_PIPES 530a04a10f8SKris Kennaway /* We are the parent. Close the child sides of the pipes. */ 531a04a10f8SKris Kennaway close(pin[0]); 532a04a10f8SKris Kennaway close(pout[1]); 533a04a10f8SKris Kennaway close(perr[1]); 534a04a10f8SKris Kennaway 5354f52dfbbSDag-Erling Smørgrav session_set_fds(ssh, s, pin[1], pout[0], perr[0], 536e2f6069cSDag-Erling Smørgrav s->is_subsystem, 0); 537d4af9e69SDag-Erling Smørgrav #else 538a04a10f8SKris Kennaway /* We are the parent. Close the child sides of the socket pairs. */ 539a04a10f8SKris Kennaway close(inout[0]); 540a04a10f8SKris Kennaway close(err[0]); 541a04a10f8SKris Kennaway 542a04a10f8SKris Kennaway /* 543a04a10f8SKris Kennaway * Enter the interactive session. Note: server_loop must be able to 544a04a10f8SKris Kennaway * handle the case that fdin and fdout are the same. 545a04a10f8SKris Kennaway */ 54619261079SEd Maste session_set_fds(ssh, s, inout[1], inout[1], err[1], 547e2f6069cSDag-Erling Smørgrav s->is_subsystem, 0); 548d4af9e69SDag-Erling Smørgrav #endif 549d4af9e69SDag-Erling Smørgrav return 0; 550a04a10f8SKris Kennaway } 551a04a10f8SKris Kennaway 552a04a10f8SKris Kennaway /* 553a04a10f8SKris Kennaway * This is called to fork and execute a command when we have a tty. This 554a04a10f8SKris Kennaway * will call do_child from the child, and server_loop from the parent after 555a04a10f8SKris Kennaway * setting up file descriptors, controlling tty, updating wtmp, utmp, 556a04a10f8SKris Kennaway * lastlog, and other such operations. 557a04a10f8SKris Kennaway */ 558d4af9e69SDag-Erling Smørgrav int 5594f52dfbbSDag-Erling Smørgrav do_exec_pty(struct ssh *ssh, Session *s, const char *command) 560a04a10f8SKris Kennaway { 561a04a10f8SKris Kennaway int fdout, ptyfd, ttyfd, ptymaster; 562a04a10f8SKris Kennaway pid_t pid; 563a04a10f8SKris Kennaway 564a04a10f8SKris Kennaway if (s == NULL) 565a04a10f8SKris Kennaway fatal("do_exec_pty: no session"); 566a04a10f8SKris Kennaway ptyfd = s->ptyfd; 567a04a10f8SKris Kennaway ttyfd = s->ttyfd; 568a04a10f8SKris Kennaway 569d4af9e69SDag-Erling Smørgrav /* 570d4af9e69SDag-Erling Smørgrav * Create another descriptor of the pty master side for use as the 571d4af9e69SDag-Erling Smørgrav * standard input. We could use the original descriptor, but this 572d4af9e69SDag-Erling Smørgrav * simplifies code in server_loop. The descriptor is bidirectional. 573d4af9e69SDag-Erling Smørgrav * Do this before forking (and cleanup in the child) so as to 574d4af9e69SDag-Erling Smørgrav * detect and gracefully fail out-of-fd conditions. 575d4af9e69SDag-Erling Smørgrav */ 57619261079SEd Maste if ((fdout = dup(ptyfd)) == -1) { 57719261079SEd Maste error_f("dup #1: %s", strerror(errno)); 578d4af9e69SDag-Erling Smørgrav close(ttyfd); 579d4af9e69SDag-Erling Smørgrav close(ptyfd); 580d4af9e69SDag-Erling Smørgrav return -1; 581cf2b5f3bSDag-Erling Smørgrav } 582d4af9e69SDag-Erling Smørgrav /* we keep a reference to the pty master */ 58319261079SEd Maste if ((ptymaster = dup(ptyfd)) == -1) { 58419261079SEd Maste error_f("dup #2: %s", strerror(errno)); 585d4af9e69SDag-Erling Smørgrav close(ttyfd); 586d4af9e69SDag-Erling Smørgrav close(ptyfd); 587d4af9e69SDag-Erling Smørgrav close(fdout); 588d4af9e69SDag-Erling Smørgrav return -1; 589d4af9e69SDag-Erling Smørgrav } 59009958426SBrian Feldman 591a04a10f8SKris Kennaway /* Fork the child. */ 592d4af9e69SDag-Erling Smørgrav switch ((pid = fork())) { 593d4af9e69SDag-Erling Smørgrav case -1: 59419261079SEd Maste error_f("fork: %.100s", strerror(errno)); 595d4af9e69SDag-Erling Smørgrav close(fdout); 596d4af9e69SDag-Erling Smørgrav close(ptymaster); 597d4af9e69SDag-Erling Smørgrav close(ttyfd); 598d4af9e69SDag-Erling Smørgrav close(ptyfd); 599d4af9e69SDag-Erling Smørgrav return -1; 600d4af9e69SDag-Erling Smørgrav case 0: 6011ec0d754SDag-Erling Smørgrav is_child = 1; 602af12a3e7SDag-Erling Smørgrav 603d4af9e69SDag-Erling Smørgrav close(fdout); 604d4af9e69SDag-Erling Smørgrav close(ptymaster); 605d4af9e69SDag-Erling Smørgrav 606a04a10f8SKris Kennaway /* Close the master side of the pseudo tty. */ 607a04a10f8SKris Kennaway close(ptyfd); 608a04a10f8SKris Kennaway 609a04a10f8SKris Kennaway /* Make the pseudo tty our controlling tty. */ 610a04a10f8SKris Kennaway pty_make_controlling_tty(&ttyfd, s->tty); 611a04a10f8SKris Kennaway 612af12a3e7SDag-Erling Smørgrav /* Redirect stdin/stdout/stderr from the pseudo tty. */ 61319261079SEd Maste if (dup2(ttyfd, 0) == -1) 614af12a3e7SDag-Erling Smørgrav error("dup2 stdin: %s", strerror(errno)); 61519261079SEd Maste if (dup2(ttyfd, 1) == -1) 616af12a3e7SDag-Erling Smørgrav error("dup2 stdout: %s", strerror(errno)); 61719261079SEd Maste if (dup2(ttyfd, 2) == -1) 618af12a3e7SDag-Erling Smørgrav error("dup2 stderr: %s", strerror(errno)); 619a04a10f8SKris Kennaway 620a04a10f8SKris Kennaway /* Close the extra descriptor for the pseudo tty. */ 621a04a10f8SKris Kennaway close(ttyfd); 622a04a10f8SKris Kennaway 623c2d3a559SKris Kennaway /* record login, etc. similar to login(1) */ 624ca86bcf2SDag-Erling Smørgrav #ifndef HAVE_OSF_SIA 6254f52dfbbSDag-Erling Smørgrav do_login(ssh, s, command); 626989dd127SDag-Erling Smørgrav #endif 627d4af9e69SDag-Erling Smørgrav /* 628d4af9e69SDag-Erling Smørgrav * Do common processing for the child, such as execing 629d4af9e69SDag-Erling Smørgrav * the command. 630d4af9e69SDag-Erling Smørgrav */ 6314f52dfbbSDag-Erling Smørgrav do_child(ssh, s, command); 632a04a10f8SKris Kennaway /* NOTREACHED */ 633d4af9e69SDag-Erling Smørgrav default: 634d4af9e69SDag-Erling Smørgrav break; 635a04a10f8SKris Kennaway } 636d4af9e69SDag-Erling Smørgrav 637989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN 638989dd127SDag-Erling Smørgrav cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); 639989dd127SDag-Erling Smørgrav #endif 640d4af9e69SDag-Erling Smørgrav 641a04a10f8SKris Kennaway s->pid = pid; 642a04a10f8SKris Kennaway 643a04a10f8SKris Kennaway /* Parent. Close the slave side of the pseudo tty. */ 644a04a10f8SKris Kennaway close(ttyfd); 645a04a10f8SKris Kennaway 646a04a10f8SKris Kennaway /* Enter interactive session. */ 647d4af9e69SDag-Erling Smørgrav s->ptymaster = ptymaster; 64819261079SEd Maste ssh_packet_set_interactive(ssh, 1, 6494a421b63SDag-Erling Smørgrav options.ip_qos_interactive, options.ip_qos_bulk); 6504f52dfbbSDag-Erling Smørgrav session_set_fds(ssh, s, ptyfd, fdout, -1, 1, 1); 651d4af9e69SDag-Erling Smørgrav return 0; 652a04a10f8SKris Kennaway } 653a04a10f8SKris Kennaway 654af12a3e7SDag-Erling Smørgrav /* 655af12a3e7SDag-Erling Smørgrav * This is called to fork and execute a command. If another command is 656af12a3e7SDag-Erling Smørgrav * to be forced, execute that instead. 657af12a3e7SDag-Erling Smørgrav */ 658d4af9e69SDag-Erling Smørgrav int 6594f52dfbbSDag-Erling Smørgrav do_exec(struct ssh *ssh, Session *s, const char *command) 660af12a3e7SDag-Erling Smørgrav { 661d4af9e69SDag-Erling Smørgrav int ret; 662acc1a9efSDag-Erling Smørgrav const char *forced = NULL, *tty = NULL; 663acc1a9efSDag-Erling Smørgrav char session_type[1024]; 664d4af9e69SDag-Erling Smørgrav 665333ee039SDag-Erling Smørgrav if (options.adm_forced_command) { 666333ee039SDag-Erling Smørgrav original_command = command; 667333ee039SDag-Erling Smørgrav command = options.adm_forced_command; 668f7167e0eSDag-Erling Smørgrav forced = "(config)"; 66947dd1d1bSDag-Erling Smørgrav } else if (auth_opts->force_command != NULL) { 670af12a3e7SDag-Erling Smørgrav original_command = command; 67147dd1d1bSDag-Erling Smørgrav command = auth_opts->force_command; 672f7167e0eSDag-Erling Smørgrav forced = "(key-option)"; 673f7167e0eSDag-Erling Smørgrav } 6742f513db7SEd Maste s->forced = 0; 675f7167e0eSDag-Erling Smørgrav if (forced != NULL) { 6762f513db7SEd Maste s->forced = 1; 677b15c8340SDag-Erling Smørgrav if (IS_INTERNAL_SFTP(command)) { 678b15c8340SDag-Erling Smørgrav s->is_subsystem = s->is_subsystem ? 679b15c8340SDag-Erling Smørgrav SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR; 680b15c8340SDag-Erling Smørgrav } else if (s->is_subsystem) 681d4af9e69SDag-Erling Smørgrav s->is_subsystem = SUBSYSTEM_EXT; 682f7167e0eSDag-Erling Smørgrav snprintf(session_type, sizeof(session_type), 683f7167e0eSDag-Erling Smørgrav "forced-command %s '%.900s'", forced, command); 684f7167e0eSDag-Erling Smørgrav } else if (s->is_subsystem) { 685f7167e0eSDag-Erling Smørgrav snprintf(session_type, sizeof(session_type), 686f7167e0eSDag-Erling Smørgrav "subsystem '%.900s'", s->subsys); 687f7167e0eSDag-Erling Smørgrav } else if (command == NULL) { 688f7167e0eSDag-Erling Smørgrav snprintf(session_type, sizeof(session_type), "shell"); 689f7167e0eSDag-Erling Smørgrav } else { 690f7167e0eSDag-Erling Smørgrav /* NB. we don't log unforced commands to preserve privacy */ 691f7167e0eSDag-Erling Smørgrav snprintf(session_type, sizeof(session_type), "command"); 692af12a3e7SDag-Erling Smørgrav } 693af12a3e7SDag-Erling Smørgrav 694f7167e0eSDag-Erling Smørgrav if (s->ttyfd != -1) { 695f7167e0eSDag-Erling Smørgrav tty = s->tty; 696f7167e0eSDag-Erling Smørgrav if (strncmp(tty, "/dev/", 5) == 0) 697f7167e0eSDag-Erling Smørgrav tty += 5; 698f7167e0eSDag-Erling Smørgrav } 699f7167e0eSDag-Erling Smørgrav 700acc1a9efSDag-Erling Smørgrav verbose("Starting session: %s%s%s for %s from %.200s port %d id %d", 701f7167e0eSDag-Erling Smørgrav session_type, 702f7167e0eSDag-Erling Smørgrav tty == NULL ? "" : " on ", 703f7167e0eSDag-Erling Smørgrav tty == NULL ? "" : tty, 704f7167e0eSDag-Erling Smørgrav s->pw->pw_name, 705076ad2f8SDag-Erling Smørgrav ssh_remote_ipaddr(ssh), 706076ad2f8SDag-Erling Smørgrav ssh_remote_port(ssh), 707acc1a9efSDag-Erling Smørgrav s->self); 708f7167e0eSDag-Erling Smørgrav 709aa49c926SDag-Erling Smørgrav #ifdef SSH_AUDIT_EVENTS 710aa49c926SDag-Erling Smørgrav if (command != NULL) 711aa49c926SDag-Erling Smørgrav PRIVSEP(audit_run_command(command)); 712aa49c926SDag-Erling Smørgrav else if (s->ttyfd == -1) { 713aa49c926SDag-Erling Smørgrav char *shell = s->pw->pw_shell; 714aa49c926SDag-Erling Smørgrav 715aa49c926SDag-Erling Smørgrav if (shell[0] == '\0') /* empty shell means /bin/sh */ 716aa49c926SDag-Erling Smørgrav shell =_PATH_BSHELL; 717aa49c926SDag-Erling Smørgrav PRIVSEP(audit_run_command(shell)); 718cf2b5f3bSDag-Erling Smørgrav } 719cf2b5f3bSDag-Erling Smørgrav #endif 720af12a3e7SDag-Erling Smørgrav if (s->ttyfd != -1) 7214f52dfbbSDag-Erling Smørgrav ret = do_exec_pty(ssh, s, command); 722af12a3e7SDag-Erling Smørgrav else 7234f52dfbbSDag-Erling Smørgrav ret = do_exec_no_pty(ssh, s, command); 724af12a3e7SDag-Erling Smørgrav 725af12a3e7SDag-Erling Smørgrav original_command = NULL; 726af12a3e7SDag-Erling Smørgrav 72721e764dfSDag-Erling Smørgrav /* 72821e764dfSDag-Erling Smørgrav * Clear loginmsg: it's the child's responsibility to display 72921e764dfSDag-Erling Smørgrav * it to the user, otherwise multiple sessions may accumulate 73021e764dfSDag-Erling Smørgrav * multiple copies of the login messages. 73121e764dfSDag-Erling Smørgrav */ 732190cef3dSDag-Erling Smørgrav sshbuf_reset(loginmsg); 733d4af9e69SDag-Erling Smørgrav 734d4af9e69SDag-Erling Smørgrav return ret; 73521e764dfSDag-Erling Smørgrav } 736af12a3e7SDag-Erling Smørgrav 737c2d3a559SKris Kennaway /* administrative, login(1)-like work */ 738ca3176e7SBrian Feldman void 7394f52dfbbSDag-Erling Smørgrav do_login(struct ssh *ssh, Session *s, const char *command) 740c2d3a559SKris Kennaway { 741c2d3a559SKris Kennaway socklen_t fromlen; 742c2d3a559SKris Kennaway struct sockaddr_storage from; 743c2d3a559SKris Kennaway struct passwd * pw = s->pw; 744c2d3a559SKris Kennaway pid_t pid = getpid(); 745c2d3a559SKris Kennaway 746c2d3a559SKris Kennaway /* 747c2d3a559SKris Kennaway * Get IP address of client. If the connection is not a socket, let 748c2d3a559SKris Kennaway * the address be 0.0.0.0. 749c2d3a559SKris Kennaway */ 750c2d3a559SKris Kennaway memset(&from, 0, sizeof(from)); 751c2d3a559SKris Kennaway fromlen = sizeof(from); 75219261079SEd Maste if (ssh_packet_connection_is_on_socket(ssh)) { 75319261079SEd Maste if (getpeername(ssh_packet_get_connection_in(ssh), 75419261079SEd Maste (struct sockaddr *)&from, &fromlen) == -1) { 755c2d3a559SKris Kennaway debug("getpeername: %.100s", strerror(errno)); 7561ec0d754SDag-Erling Smørgrav cleanup_exit(255); 757c2d3a559SKris Kennaway } 758c2d3a559SKris Kennaway } 759c2d3a559SKris Kennaway 76080628bacSDag-Erling Smørgrav /* Record that there was a login on that tty from the remote host. */ 76180628bacSDag-Erling Smørgrav if (!use_privsep) 76280628bacSDag-Erling Smørgrav record_login(pid, s->tty, pw->pw_name, pw->pw_uid, 763076ad2f8SDag-Erling Smørgrav session_get_remote_name_or_ip(ssh, utmp_len, 764cf2b5f3bSDag-Erling Smørgrav options.use_dns), 7657ac32603SHajimu UMEMOTO (struct sockaddr *)&from, fromlen); 76680628bacSDag-Erling Smørgrav 767098de0c1SAndrey A. Chernov #ifdef USE_PAM 768c2d3a559SKris Kennaway /* 769989dd127SDag-Erling Smørgrav * If password change is needed, do it now. 770989dd127SDag-Erling Smørgrav * This needs to occur before the ~/.hushlogin check. 771c2d3a559SKris Kennaway */ 7721ec0d754SDag-Erling Smørgrav if (options.use_pam && !use_privsep && s->authctxt->force_pwchange) { 7731ec0d754SDag-Erling Smørgrav display_loginmsg(); 774989dd127SDag-Erling Smørgrav do_pam_chauthtok(); 7751ec0d754SDag-Erling Smørgrav s->authctxt->force_pwchange = 0; 776cf2b5f3bSDag-Erling Smørgrav /* XXX - signal [net] parent to enable forwardings */ 777989dd127SDag-Erling Smørgrav } 778989dd127SDag-Erling Smørgrav #endif 779af12a3e7SDag-Erling Smørgrav 780989dd127SDag-Erling Smørgrav if (check_quietlogin(s, command)) 781989dd127SDag-Erling Smørgrav return; 782989dd127SDag-Erling Smørgrav 7831ec0d754SDag-Erling Smørgrav display_loginmsg(); 784f388f5efSDag-Erling Smørgrav 785ca3176e7SBrian Feldman do_motd(); 786ca3176e7SBrian Feldman } 787ca3176e7SBrian Feldman 788ca3176e7SBrian Feldman /* 789ca3176e7SBrian Feldman * Display the message of the day. 790ca3176e7SBrian Feldman */ 791ca3176e7SBrian Feldman void 792ca3176e7SBrian Feldman do_motd(void) 793ca3176e7SBrian Feldman { 794ca3176e7SBrian Feldman FILE *f; 795ca3176e7SBrian Feldman char buf[256]; 796ca3176e7SBrian Feldman 797ca3176e7SBrian Feldman if (options.print_motd) { 798c2d3a559SKris Kennaway #ifdef HAVE_LOGIN_CAP 799c2d3a559SKris Kennaway f = fopen(login_getcapstr(lc, "welcome", "/etc/motd", 800c2d3a559SKris Kennaway "/etc/motd"), "r"); 801af12a3e7SDag-Erling Smørgrav #else 802c2d3a559SKris Kennaway f = fopen("/etc/motd", "r"); 803af12a3e7SDag-Erling Smørgrav #endif 804c2d3a559SKris Kennaway if (f) { 805c2d3a559SKris Kennaway while (fgets(buf, sizeof(buf), f)) 806c2d3a559SKris Kennaway fputs(buf, stdout); 807c2d3a559SKris Kennaway fclose(f); 808c2d3a559SKris Kennaway } 809c2d3a559SKris Kennaway } 810ca3176e7SBrian Feldman } 811c2d3a559SKris Kennaway 812af12a3e7SDag-Erling Smørgrav 813ca3176e7SBrian Feldman /* 814ca3176e7SBrian Feldman * Check for quiet login, either .hushlogin or command given. 815ca3176e7SBrian Feldman */ 816ca3176e7SBrian Feldman int 817ca3176e7SBrian Feldman check_quietlogin(Session *s, const char *command) 818ca3176e7SBrian Feldman { 819ca3176e7SBrian Feldman char buf[256]; 820ca3176e7SBrian Feldman struct passwd *pw = s->pw; 821ca3176e7SBrian Feldman struct stat st; 822ca3176e7SBrian Feldman 823ca3176e7SBrian Feldman /* Return 1 if .hushlogin exists or a command given. */ 824ca3176e7SBrian Feldman if (command != NULL) 825ca3176e7SBrian Feldman return 1; 826ca3176e7SBrian Feldman snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir); 827c2d3a559SKris Kennaway #ifdef HAVE_LOGIN_CAP 828ca3176e7SBrian Feldman if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0) 829ca3176e7SBrian Feldman return 1; 830ca3176e7SBrian Feldman #else 831ca3176e7SBrian Feldman if (stat(buf, &st) >= 0) 832ca3176e7SBrian Feldman return 1; 833ca3176e7SBrian Feldman #endif 834ca3176e7SBrian Feldman return 0; 835c2d3a559SKris Kennaway } 836c2d3a559SKris Kennaway 837a04a10f8SKris Kennaway /* 838a04a10f8SKris Kennaway * Reads environment variables from the given file and adds/overrides them 839a04a10f8SKris Kennaway * into the environment. If the file does not exist, this does nothing. 840a04a10f8SKris Kennaway * Otherwise, it must consist of empty lines, comments (line starts with '#') 841a04a10f8SKris Kennaway * and assignments of the form name=value. No other forms are allowed. 84219261079SEd Maste * If allowlist is not NULL, then it is interpreted as a pattern list and 843190cef3dSDag-Erling Smørgrav * only variable names that match it will be accepted. 844a04a10f8SKris Kennaway */ 845af12a3e7SDag-Erling Smørgrav static void 846ca3176e7SBrian Feldman read_environment_file(char ***env, u_int *envsize, 84719261079SEd Maste const char *filename, const char *allowlist) 848a04a10f8SKris Kennaway { 849a04a10f8SKris Kennaway FILE *f; 850190cef3dSDag-Erling Smørgrav char *line = NULL, *cp, *value; 851190cef3dSDag-Erling Smørgrav size_t linesize = 0; 852a82e551fSDag-Erling Smørgrav u_int lineno = 0; 853a04a10f8SKris Kennaway 854a04a10f8SKris Kennaway f = fopen(filename, "r"); 855a04a10f8SKris Kennaway if (!f) 856a04a10f8SKris Kennaway return; 857a04a10f8SKris Kennaway 858190cef3dSDag-Erling Smørgrav while (getline(&line, &linesize, f) != -1) { 859a82e551fSDag-Erling Smørgrav if (++lineno > 1000) 860a82e551fSDag-Erling Smørgrav fatal("Too many lines in environment file %s", filename); 861190cef3dSDag-Erling Smørgrav for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 862a04a10f8SKris Kennaway ; 863a04a10f8SKris Kennaway if (!*cp || *cp == '#' || *cp == '\n') 864a04a10f8SKris Kennaway continue; 865d4af9e69SDag-Erling Smørgrav 866d4af9e69SDag-Erling Smørgrav cp[strcspn(cp, "\n")] = '\0'; 867d4af9e69SDag-Erling Smørgrav 868a04a10f8SKris Kennaway value = strchr(cp, '='); 869a04a10f8SKris Kennaway if (value == NULL) { 870a82e551fSDag-Erling Smørgrav fprintf(stderr, "Bad line %u in %.100s\n", lineno, 871a82e551fSDag-Erling Smørgrav filename); 872a04a10f8SKris Kennaway continue; 873a04a10f8SKris Kennaway } 874db1cb46cSKris Kennaway /* 875db1cb46cSKris Kennaway * Replace the equals sign by nul, and advance value to 876db1cb46cSKris Kennaway * the value string. 877db1cb46cSKris Kennaway */ 878a04a10f8SKris Kennaway *value = '\0'; 879a04a10f8SKris Kennaway value++; 88019261079SEd Maste if (allowlist != NULL && 88119261079SEd Maste match_pattern_list(cp, allowlist, 0) != 1) 882190cef3dSDag-Erling Smørgrav continue; 883a04a10f8SKris Kennaway child_set_env(env, envsize, cp, value); 884a04a10f8SKris Kennaway } 885190cef3dSDag-Erling Smørgrav free(line); 886a04a10f8SKris Kennaway fclose(f); 887a04a10f8SKris Kennaway } 888a04a10f8SKris Kennaway 889cf2b5f3bSDag-Erling Smørgrav #ifdef HAVE_ETC_DEFAULT_LOGIN 890cf2b5f3bSDag-Erling Smørgrav /* 891cf2b5f3bSDag-Erling Smørgrav * Return named variable from specified environment, or NULL if not present. 892cf2b5f3bSDag-Erling Smørgrav */ 893cf2b5f3bSDag-Erling Smørgrav static char * 894cf2b5f3bSDag-Erling Smørgrav child_get_env(char **env, const char *name) 895cf2b5f3bSDag-Erling Smørgrav { 896cf2b5f3bSDag-Erling Smørgrav int i; 897cf2b5f3bSDag-Erling Smørgrav size_t len; 898cf2b5f3bSDag-Erling Smørgrav 899cf2b5f3bSDag-Erling Smørgrav len = strlen(name); 900cf2b5f3bSDag-Erling Smørgrav for (i=0; env[i] != NULL; i++) 901cf2b5f3bSDag-Erling Smørgrav if (strncmp(name, env[i], len) == 0 && env[i][len] == '=') 902cf2b5f3bSDag-Erling Smørgrav return(env[i] + len + 1); 903cf2b5f3bSDag-Erling Smørgrav return NULL; 904cf2b5f3bSDag-Erling Smørgrav } 905cf2b5f3bSDag-Erling Smørgrav 906cf2b5f3bSDag-Erling Smørgrav /* 907cf2b5f3bSDag-Erling Smørgrav * Read /etc/default/login. 908cf2b5f3bSDag-Erling Smørgrav * We pick up the PATH (or SUPATH for root) and UMASK. 909cf2b5f3bSDag-Erling Smørgrav */ 910cf2b5f3bSDag-Erling Smørgrav static void 911cf2b5f3bSDag-Erling Smørgrav read_etc_default_login(char ***env, u_int *envsize, uid_t uid) 912cf2b5f3bSDag-Erling Smørgrav { 913cf2b5f3bSDag-Erling Smørgrav char **tmpenv = NULL, *var; 914cf2b5f3bSDag-Erling Smørgrav u_int i, tmpenvsize = 0; 9151ec0d754SDag-Erling Smørgrav u_long mask; 916cf2b5f3bSDag-Erling Smørgrav 917cf2b5f3bSDag-Erling Smørgrav /* 918cf2b5f3bSDag-Erling Smørgrav * We don't want to copy the whole file to the child's environment, 919cf2b5f3bSDag-Erling Smørgrav * so we use a temporary environment and copy the variables we're 920cf2b5f3bSDag-Erling Smørgrav * interested in. 921cf2b5f3bSDag-Erling Smørgrav */ 922190cef3dSDag-Erling Smørgrav read_environment_file(&tmpenv, &tmpenvsize, "/etc/default/login", 92319261079SEd Maste options.permit_user_env_allowlist); 924cf2b5f3bSDag-Erling Smørgrav 925cf2b5f3bSDag-Erling Smørgrav if (tmpenv == NULL) 926cf2b5f3bSDag-Erling Smørgrav return; 927cf2b5f3bSDag-Erling Smørgrav 928cf2b5f3bSDag-Erling Smørgrav if (uid == 0) 929cf2b5f3bSDag-Erling Smørgrav var = child_get_env(tmpenv, "SUPATH"); 930cf2b5f3bSDag-Erling Smørgrav else 931cf2b5f3bSDag-Erling Smørgrav var = child_get_env(tmpenv, "PATH"); 932cf2b5f3bSDag-Erling Smørgrav if (var != NULL) 933cf2b5f3bSDag-Erling Smørgrav child_set_env(env, envsize, "PATH", var); 934cf2b5f3bSDag-Erling Smørgrav 935cf2b5f3bSDag-Erling Smørgrav if ((var = child_get_env(tmpenv, "UMASK")) != NULL) 936cf2b5f3bSDag-Erling Smørgrav if (sscanf(var, "%5lo", &mask) == 1) 9371ec0d754SDag-Erling Smørgrav umask((mode_t)mask); 938cf2b5f3bSDag-Erling Smørgrav 939cf2b5f3bSDag-Erling Smørgrav for (i = 0; tmpenv[i] != NULL; i++) 940e4a9863fSDag-Erling Smørgrav free(tmpenv[i]); 941e4a9863fSDag-Erling Smørgrav free(tmpenv); 942cf2b5f3bSDag-Erling Smørgrav } 943cf2b5f3bSDag-Erling Smørgrav #endif /* HAVE_ETC_DEFAULT_LOGIN */ 944cf2b5f3bSDag-Erling Smørgrav 94519261079SEd Maste #if defined(USE_PAM) || defined(HAVE_CYGWIN) 9464f52dfbbSDag-Erling Smørgrav static void 94719261079SEd Maste copy_environment_denylist(char **source, char ***env, u_int *envsize, 94819261079SEd Maste const char *denylist) 94909958426SBrian Feldman { 950989dd127SDag-Erling Smørgrav char *var_name, *var_val; 95109958426SBrian Feldman int i; 95209958426SBrian Feldman 953989dd127SDag-Erling Smørgrav if (source == NULL) 95409958426SBrian Feldman return; 95509958426SBrian Feldman 956989dd127SDag-Erling Smørgrav for(i = 0; source[i] != NULL; i++) { 957989dd127SDag-Erling Smørgrav var_name = xstrdup(source[i]); 958989dd127SDag-Erling Smørgrav if ((var_val = strstr(var_name, "=")) == NULL) { 959e4a9863fSDag-Erling Smørgrav free(var_name); 96009958426SBrian Feldman continue; 961989dd127SDag-Erling Smørgrav } 962989dd127SDag-Erling Smørgrav *var_val++ = '\0'; 96309958426SBrian Feldman 96419261079SEd Maste if (denylist == NULL || 96519261079SEd Maste match_pattern_list(var_name, denylist, 0) != 1) { 966989dd127SDag-Erling Smørgrav debug3("Copy environment: %s=%s", var_name, var_val); 96709958426SBrian Feldman child_set_env(env, envsize, var_name, var_val); 9684f52dfbbSDag-Erling Smørgrav } 969989dd127SDag-Erling Smørgrav 970e4a9863fSDag-Erling Smørgrav free(var_name); 97109958426SBrian Feldman } 97209958426SBrian Feldman } 97319261079SEd Maste #endif /* defined(USE_PAM) || defined(HAVE_CYGWIN) */ 97409958426SBrian Feldman 97519261079SEd Maste #ifdef HAVE_CYGWIN 97619261079SEd Maste static void 9774f52dfbbSDag-Erling Smørgrav copy_environment(char **source, char ***env, u_int *envsize) 978a04a10f8SKris Kennaway { 97919261079SEd Maste copy_environment_denylist(source, env, envsize, NULL); 9804f52dfbbSDag-Erling Smørgrav } 98119261079SEd Maste #endif 9824f52dfbbSDag-Erling Smørgrav 9834f52dfbbSDag-Erling Smørgrav static char ** 9844f52dfbbSDag-Erling Smørgrav do_setup_env(struct ssh *ssh, Session *s, const char *shell) 9854f52dfbbSDag-Erling Smørgrav { 986a04a10f8SKris Kennaway char buf[256]; 98747dd1d1bSDag-Erling Smørgrav size_t n; 988af12a3e7SDag-Erling Smørgrav u_int i, envsize; 989190cef3dSDag-Erling Smørgrav char *ocp, *cp, *value, **env, *laddr; 990333ee039SDag-Erling Smørgrav struct passwd *pw = s->pw; 9917aee6ffeSDag-Erling Smørgrav #if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN) 992333ee039SDag-Erling Smørgrav char *path = NULL; 993333ee039SDag-Erling Smørgrav #else 994c62005fcSDag-Erling Smørgrav extern char **environ; 995ca86bcf2SDag-Erling Smørgrav char **senv, **var, *val; 996c62005fcSDag-Erling Smørgrav #endif 997a04a10f8SKris Kennaway 998a04a10f8SKris Kennaway /* Initialize the environment. */ 999a04a10f8SKris Kennaway envsize = 100; 1000333ee039SDag-Erling Smørgrav env = xcalloc(envsize, sizeof(char *)); 1001a04a10f8SKris Kennaway env[0] = NULL; 1002989dd127SDag-Erling Smørgrav 1003989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN 1004989dd127SDag-Erling Smørgrav /* 1005989dd127SDag-Erling Smørgrav * The Windows environment contains some setting which are 1006989dd127SDag-Erling Smørgrav * important for a running system. They must not be dropped. 1007989dd127SDag-Erling Smørgrav */ 1008aa49c926SDag-Erling Smørgrav { 1009aa49c926SDag-Erling Smørgrav char **p; 1010aa49c926SDag-Erling Smørgrav 1011aa49c926SDag-Erling Smørgrav p = fetch_windows_environment(); 1012aa49c926SDag-Erling Smørgrav copy_environment(p, &env, &envsize); 1013aa49c926SDag-Erling Smørgrav free_windows_environment(p); 1014aa49c926SDag-Erling Smørgrav } 1015989dd127SDag-Erling Smørgrav #endif 1016a04a10f8SKris Kennaway 1017c62005fcSDag-Erling Smørgrav if (getenv("TZ")) 1018c62005fcSDag-Erling Smørgrav child_set_env(&env, &envsize, "TZ", getenv("TZ")); 1019cf2b5f3bSDag-Erling Smørgrav 1020cf2b5f3bSDag-Erling Smørgrav #ifdef GSSAPI 1021cf2b5f3bSDag-Erling Smørgrav /* Allow any GSSAPI methods that we've used to alter 102219261079SEd Maste * the child's environment as they see fit 1023cf2b5f3bSDag-Erling Smørgrav */ 1024cf2b5f3bSDag-Erling Smørgrav ssh_gssapi_do_child(&env, &envsize); 1025cf2b5f3bSDag-Erling Smørgrav #endif 1026cf2b5f3bSDag-Erling Smørgrav 1027a04a10f8SKris Kennaway /* Set basic environment. */ 102821e764dfSDag-Erling Smørgrav for (i = 0; i < s->num_env; i++) 1029ca86bcf2SDag-Erling Smørgrav child_set_env(&env, &envsize, s->env[i].name, s->env[i].val); 103021e764dfSDag-Erling Smørgrav 1031a04a10f8SKris Kennaway child_set_env(&env, &envsize, "USER", pw->pw_name); 1032a04a10f8SKris Kennaway child_set_env(&env, &envsize, "LOGNAME", pw->pw_name); 1033e73e9afaSDag-Erling Smørgrav #ifdef _AIX 1034e73e9afaSDag-Erling Smørgrav child_set_env(&env, &envsize, "LOGIN", pw->pw_name); 1035e73e9afaSDag-Erling Smørgrav #endif 1036a04a10f8SKris Kennaway child_set_env(&env, &envsize, "HOME", pw->pw_dir); 1037ca86bcf2SDag-Erling Smørgrav snprintf(buf, sizeof buf, "%.200s/%.50s", _PATH_MAILDIR, pw->pw_name); 1038c62005fcSDag-Erling Smørgrav child_set_env(&env, &envsize, "MAIL", buf); 1039989dd127SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP 1040c62005fcSDag-Erling Smørgrav child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); 1041c62005fcSDag-Erling Smørgrav child_set_env(&env, &envsize, "TERM", "su"); 1042ca86bcf2SDag-Erling Smørgrav /* 1043ca86bcf2SDag-Erling Smørgrav * Temporarily swap out our real environment with an empty one, 1044ca86bcf2SDag-Erling Smørgrav * let setusercontext() apply any environment variables defined 1045ca86bcf2SDag-Erling Smørgrav * for the user's login class, copy those variables to the child, 1046ca86bcf2SDag-Erling Smørgrav * free the temporary environment, and restore the original. 1047ca86bcf2SDag-Erling Smørgrav */ 1048c62005fcSDag-Erling Smørgrav senv = environ; 1049ca86bcf2SDag-Erling Smørgrav environ = xmalloc(sizeof(*environ)); 1050c62005fcSDag-Erling Smørgrav *environ = NULL; 1051ca86bcf2SDag-Erling Smørgrav (void)setusercontext(lc, pw, pw->pw_uid, LOGIN_SETENV|LOGIN_SETPATH); 1052ca86bcf2SDag-Erling Smørgrav for (var = environ; *var != NULL; ++var) { 1053ca86bcf2SDag-Erling Smørgrav if ((val = strchr(*var, '=')) != NULL) { 1054ca86bcf2SDag-Erling Smørgrav *val++ = '\0'; 1055ca86bcf2SDag-Erling Smørgrav child_set_env(&env, &envsize, *var, val); 1056ca86bcf2SDag-Erling Smørgrav } 1057e4a9863fSDag-Erling Smørgrav free(*var); 1058ca86bcf2SDag-Erling Smørgrav } 1059e4a9863fSDag-Erling Smørgrav free(environ); 1060c62005fcSDag-Erling Smørgrav environ = senv; 1061989dd127SDag-Erling Smørgrav #else /* HAVE_LOGIN_CAP */ 1062989dd127SDag-Erling Smørgrav # ifndef HAVE_CYGWIN 1063989dd127SDag-Erling Smørgrav /* 1064989dd127SDag-Erling Smørgrav * There's no standard path on Windows. The path contains 1065989dd127SDag-Erling Smørgrav * important components pointing to the system directories, 1066989dd127SDag-Erling Smørgrav * needed for loading shared libraries. So the path better 1067989dd127SDag-Erling Smørgrav * remains intact here. 1068989dd127SDag-Erling Smørgrav */ 1069cf2b5f3bSDag-Erling Smørgrav # ifdef HAVE_ETC_DEFAULT_LOGIN 1070cf2b5f3bSDag-Erling Smørgrav read_etc_default_login(&env, &envsize, pw->pw_uid); 1071cf2b5f3bSDag-Erling Smørgrav path = child_get_env(env, "PATH"); 1072cf2b5f3bSDag-Erling Smørgrav # endif /* HAVE_ETC_DEFAULT_LOGIN */ 1073cf2b5f3bSDag-Erling Smørgrav if (path == NULL || *path == '\0') { 1074989dd127SDag-Erling Smørgrav child_set_env(&env, &envsize, "PATH", 1075ca86bcf2SDag-Erling Smørgrav s->pw->pw_uid == 0 ? SUPERUSER_PATH : _PATH_STDPATH); 1076cf2b5f3bSDag-Erling Smørgrav } 1077989dd127SDag-Erling Smørgrav # endif /* HAVE_CYGWIN */ 1078989dd127SDag-Erling Smørgrav #endif /* HAVE_LOGIN_CAP */ 1079a04a10f8SKris Kennaway 108019261079SEd Maste if (!options.use_pam) { 108119261079SEd Maste snprintf(buf, sizeof buf, "%.200s/%.50s", 108219261079SEd Maste _PATH_MAILDIR, pw->pw_name); 108319261079SEd Maste child_set_env(&env, &envsize, "MAIL", buf); 108419261079SEd Maste } 108519261079SEd Maste 1086a04a10f8SKris Kennaway /* Normal systems set SHELL by default. */ 1087a04a10f8SKris Kennaway child_set_env(&env, &envsize, "SHELL", shell); 1088ca86bcf2SDag-Erling Smørgrav 1089ca3176e7SBrian Feldman if (s->term) 1090ca3176e7SBrian Feldman child_set_env(&env, &envsize, "TERM", s->term); 1091ca3176e7SBrian Feldman if (s->display) 1092ca3176e7SBrian Feldman child_set_env(&env, &envsize, "DISPLAY", s->display); 1093989dd127SDag-Erling Smørgrav 1094aa49c926SDag-Erling Smørgrav /* 1095aa49c926SDag-Erling Smørgrav * Since we clear KRB5CCNAME at startup, if it's set now then it 1096aa49c926SDag-Erling Smørgrav * must have been set by a native authentication method (eg AIX or 1097aa49c926SDag-Erling Smørgrav * SIA), so copy it to the child. 1098aa49c926SDag-Erling Smørgrav */ 1099aa49c926SDag-Erling Smørgrav { 1100aa49c926SDag-Erling Smørgrav char *cp; 1101aa49c926SDag-Erling Smørgrav 1102aa49c926SDag-Erling Smørgrav if ((cp = getenv("KRB5CCNAME")) != NULL) 1103aa49c926SDag-Erling Smørgrav child_set_env(&env, &envsize, "KRB5CCNAME", cp); 1104aa49c926SDag-Erling Smørgrav } 1105aa49c926SDag-Erling Smørgrav 1106989dd127SDag-Erling Smørgrav #ifdef _AIX 1107989dd127SDag-Erling Smørgrav { 1108989dd127SDag-Erling Smørgrav char *cp; 1109989dd127SDag-Erling Smørgrav 1110989dd127SDag-Erling Smørgrav if ((cp = getenv("AUTHSTATE")) != NULL) 1111989dd127SDag-Erling Smørgrav child_set_env(&env, &envsize, "AUTHSTATE", cp); 1112190cef3dSDag-Erling Smørgrav read_environment_file(&env, &envsize, "/etc/environment", 111319261079SEd Maste options.permit_user_env_allowlist); 1114989dd127SDag-Erling Smørgrav } 1115989dd127SDag-Erling Smørgrav #endif 1116e8aafc91SKris Kennaway #ifdef KRB5 11175962c0e9SDag-Erling Smørgrav if (s->authctxt->krb5_ccname) 1118af12a3e7SDag-Erling Smørgrav child_set_env(&env, &envsize, "KRB5CCNAME", 11195962c0e9SDag-Erling Smørgrav s->authctxt->krb5_ccname); 1120af12a3e7SDag-Erling Smørgrav #endif 1121190cef3dSDag-Erling Smørgrav if (auth_sock_name != NULL) 1122190cef3dSDag-Erling Smørgrav child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, 1123190cef3dSDag-Erling Smørgrav auth_sock_name); 1124190cef3dSDag-Erling Smørgrav 1125190cef3dSDag-Erling Smørgrav 1126190cef3dSDag-Erling Smørgrav /* Set custom environment options from pubkey authentication. */ 1127190cef3dSDag-Erling Smørgrav if (options.permit_user_env) { 1128190cef3dSDag-Erling Smørgrav for (n = 0 ; n < auth_opts->nenv; n++) { 1129190cef3dSDag-Erling Smørgrav ocp = xstrdup(auth_opts->env[n]); 1130190cef3dSDag-Erling Smørgrav cp = strchr(ocp, '='); 113119261079SEd Maste if (cp != NULL) { 1132190cef3dSDag-Erling Smørgrav *cp = '\0'; 113319261079SEd Maste /* Apply PermitUserEnvironment allowlist */ 113419261079SEd Maste if (options.permit_user_env_allowlist == NULL || 1135190cef3dSDag-Erling Smørgrav match_pattern_list(ocp, 113619261079SEd Maste options.permit_user_env_allowlist, 0) == 1) 1137190cef3dSDag-Erling Smørgrav child_set_env(&env, &envsize, 1138190cef3dSDag-Erling Smørgrav ocp, cp + 1); 1139190cef3dSDag-Erling Smørgrav } 1140190cef3dSDag-Erling Smørgrav free(ocp); 1141190cef3dSDag-Erling Smørgrav } 1142190cef3dSDag-Erling Smørgrav } 1143190cef3dSDag-Erling Smørgrav 1144190cef3dSDag-Erling Smørgrav /* read $HOME/.ssh/environment. */ 1145190cef3dSDag-Erling Smørgrav if (options.permit_user_env) { 114619261079SEd Maste snprintf(buf, sizeof buf, "%.200s/%s/environment", 114719261079SEd Maste pw->pw_dir, _PATH_SSH_USER_DIR); 1148190cef3dSDag-Erling Smørgrav read_environment_file(&env, &envsize, buf, 114919261079SEd Maste options.permit_user_env_allowlist); 1150190cef3dSDag-Erling Smørgrav } 1151190cef3dSDag-Erling Smørgrav 115209958426SBrian Feldman #ifdef USE_PAM 1153f388f5efSDag-Erling Smørgrav /* 1154f388f5efSDag-Erling Smørgrav * Pull in any environment variables that may have 1155f388f5efSDag-Erling Smørgrav * been set by PAM. 1156f388f5efSDag-Erling Smørgrav */ 1157ca86bcf2SDag-Erling Smørgrav if (options.use_pam) { 11581ec0d754SDag-Erling Smørgrav char **p; 1159f388f5efSDag-Erling Smørgrav 11604f52dfbbSDag-Erling Smørgrav /* 116119261079SEd Maste * Don't allow PAM-internal env vars to leak 116219261079SEd Maste * back into the session environment. 11634f52dfbbSDag-Erling Smørgrav */ 116419261079SEd Maste #define PAM_ENV_DENYLIST "SSH_AUTH_INFO*,SSH_CONNECTION*" 11651ec0d754SDag-Erling Smørgrav p = fetch_pam_child_environment(); 116619261079SEd Maste copy_environment_denylist(p, &env, &envsize, 116719261079SEd Maste PAM_ENV_DENYLIST); 11681ec0d754SDag-Erling Smørgrav free_pam_environment(p); 11691ec0d754SDag-Erling Smørgrav 11701ec0d754SDag-Erling Smørgrav p = fetch_pam_environment(); 117119261079SEd Maste copy_environment_denylist(p, &env, &envsize, 117219261079SEd Maste PAM_ENV_DENYLIST); 1173f388f5efSDag-Erling Smørgrav free_pam_environment(p); 1174f388f5efSDag-Erling Smørgrav } 117509958426SBrian Feldman #endif /* USE_PAM */ 117609958426SBrian Feldman 1177190cef3dSDag-Erling Smørgrav /* Environment specified by admin */ 1178190cef3dSDag-Erling Smørgrav for (i = 0; i < options.num_setenv; i++) { 1179190cef3dSDag-Erling Smørgrav cp = xstrdup(options.setenv[i]); 1180190cef3dSDag-Erling Smørgrav if ((value = strchr(cp, '=')) == NULL) { 1181190cef3dSDag-Erling Smørgrav /* shouldn't happen; vars are checked in servconf.c */ 1182190cef3dSDag-Erling Smørgrav fatal("Invalid config SetEnv: %s", options.setenv[i]); 1183a04a10f8SKris Kennaway } 1184190cef3dSDag-Erling Smørgrav *value++ = '\0'; 1185190cef3dSDag-Erling Smørgrav child_set_env(&env, &envsize, cp, value); 1186190cef3dSDag-Erling Smørgrav } 1187190cef3dSDag-Erling Smørgrav 1188190cef3dSDag-Erling Smørgrav /* SSH_CLIENT deprecated */ 1189190cef3dSDag-Erling Smørgrav snprintf(buf, sizeof buf, "%.50s %d %d", 1190190cef3dSDag-Erling Smørgrav ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), 1191190cef3dSDag-Erling Smørgrav ssh_local_port(ssh)); 1192190cef3dSDag-Erling Smørgrav child_set_env(&env, &envsize, "SSH_CLIENT", buf); 1193190cef3dSDag-Erling Smørgrav 119419261079SEd Maste laddr = get_local_ipaddr(ssh_packet_get_connection_in(ssh)); 1195190cef3dSDag-Erling Smørgrav snprintf(buf, sizeof buf, "%.50s %d %.50s %d", 1196190cef3dSDag-Erling Smørgrav ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), 1197190cef3dSDag-Erling Smørgrav laddr, ssh_local_port(ssh)); 1198190cef3dSDag-Erling Smørgrav free(laddr); 1199190cef3dSDag-Erling Smørgrav child_set_env(&env, &envsize, "SSH_CONNECTION", buf); 1200190cef3dSDag-Erling Smørgrav 1201190cef3dSDag-Erling Smørgrav if (tun_fwd_ifnames != NULL) 1202190cef3dSDag-Erling Smørgrav child_set_env(&env, &envsize, "SSH_TUNNEL", tun_fwd_ifnames); 1203190cef3dSDag-Erling Smørgrav if (auth_info_file != NULL) 1204190cef3dSDag-Erling Smørgrav child_set_env(&env, &envsize, "SSH_USER_AUTH", auth_info_file); 1205190cef3dSDag-Erling Smørgrav if (s->ttyfd != -1) 1206190cef3dSDag-Erling Smørgrav child_set_env(&env, &envsize, "SSH_TTY", s->tty); 1207190cef3dSDag-Erling Smørgrav if (original_command) 1208190cef3dSDag-Erling Smørgrav child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND", 1209190cef3dSDag-Erling Smørgrav original_command); 1210190cef3dSDag-Erling Smørgrav 1211a04a10f8SKris Kennaway if (debug_flag) { 1212a04a10f8SKris Kennaway /* dump the environment */ 1213a04a10f8SKris Kennaway fprintf(stderr, "Environment:\n"); 1214a04a10f8SKris Kennaway for (i = 0; env[i]; i++) 1215a04a10f8SKris Kennaway fprintf(stderr, " %.200s\n", env[i]); 1216a04a10f8SKris Kennaway } 1217af12a3e7SDag-Erling Smørgrav return env; 1218e8aafc91SKris Kennaway } 1219ca3176e7SBrian Feldman 1220ca3176e7SBrian Feldman /* 1221af12a3e7SDag-Erling Smørgrav * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found 1222af12a3e7SDag-Erling Smørgrav * first in this order). 1223ca3176e7SBrian Feldman */ 1224af12a3e7SDag-Erling Smørgrav static void 122547dd1d1bSDag-Erling Smørgrav do_rc_files(struct ssh *ssh, Session *s, const char *shell) 1226af12a3e7SDag-Erling Smørgrav { 1227af12a3e7SDag-Erling Smørgrav FILE *f = NULL; 122819261079SEd Maste char *cmd = NULL, *user_rc = NULL; 1229af12a3e7SDag-Erling Smørgrav int do_xauth; 1230af12a3e7SDag-Erling Smørgrav struct stat st; 1231a04a10f8SKris Kennaway 1232af12a3e7SDag-Erling Smørgrav do_xauth = 1233af12a3e7SDag-Erling Smørgrav s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL; 123419261079SEd Maste xasprintf(&user_rc, "%s/%s", s->pw->pw_dir, _PATH_SSH_USER_RC); 1235a04a10f8SKris Kennaway 1236d4af9e69SDag-Erling Smørgrav /* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */ 1237d4af9e69SDag-Erling Smørgrav if (!s->is_subsystem && options.adm_forced_command == NULL && 123847dd1d1bSDag-Erling Smørgrav auth_opts->permit_user_rc && options.permit_user_rc && 123919261079SEd Maste stat(user_rc, &st) >= 0) { 124019261079SEd Maste if (xasprintf(&cmd, "%s -c '%s %s'", shell, _PATH_BSHELL, 124119261079SEd Maste user_rc) == -1) 124219261079SEd Maste fatal_f("xasprintf: %s", strerror(errno)); 1243a04a10f8SKris Kennaway if (debug_flag) 1244e9fd63dfSBrian Feldman fprintf(stderr, "Running %s\n", cmd); 1245e9fd63dfSBrian Feldman f = popen(cmd, "w"); 1246a04a10f8SKris Kennaway if (f) { 1247ca3176e7SBrian Feldman if (do_xauth) 1248ca3176e7SBrian Feldman fprintf(f, "%s %s\n", s->auth_proto, 1249ca3176e7SBrian Feldman s->auth_data); 1250a04a10f8SKris Kennaway pclose(f); 1251a04a10f8SKris Kennaway } else 1252ca3176e7SBrian Feldman fprintf(stderr, "Could not run %s\n", 125319261079SEd Maste user_rc); 1254ca3176e7SBrian Feldman } else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) { 1255a04a10f8SKris Kennaway if (debug_flag) 1256ca3176e7SBrian Feldman fprintf(stderr, "Running %s %s\n", _PATH_BSHELL, 1257ca3176e7SBrian Feldman _PATH_SSH_SYSTEM_RC); 1258ca3176e7SBrian Feldman f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w"); 1259a04a10f8SKris Kennaway if (f) { 1260ca3176e7SBrian Feldman if (do_xauth) 1261ca3176e7SBrian Feldman fprintf(f, "%s %s\n", s->auth_proto, 1262ca3176e7SBrian Feldman s->auth_data); 1263a04a10f8SKris Kennaway pclose(f); 1264a04a10f8SKris Kennaway } else 1265ca3176e7SBrian Feldman fprintf(stderr, "Could not run %s\n", 1266ca3176e7SBrian Feldman _PATH_SSH_SYSTEM_RC); 1267ca3176e7SBrian Feldman } else if (do_xauth && options.xauth_location != NULL) { 1268a04a10f8SKris Kennaway /* Add authority data to .Xauthority if appropriate. */ 1269db1cb46cSKris Kennaway if (debug_flag) { 1270db1cb46cSKris Kennaway fprintf(stderr, 1271e73e9afaSDag-Erling Smørgrav "Running %.500s remove %.100s\n", 1272e73e9afaSDag-Erling Smørgrav options.xauth_location, s->auth_display); 1273e73e9afaSDag-Erling Smørgrav fprintf(stderr, 1274e73e9afaSDag-Erling Smørgrav "%.500s add %.100s %.100s %.100s\n", 1275af12a3e7SDag-Erling Smørgrav options.xauth_location, s->auth_display, 1276ca3176e7SBrian Feldman s->auth_proto, s->auth_data); 1277db1cb46cSKris Kennaway } 127819261079SEd Maste if (xasprintf(&cmd, "%s -q -", options.xauth_location) == -1) 127919261079SEd Maste fatal_f("xasprintf: %s", strerror(errno)); 1280c2d3a559SKris Kennaway f = popen(cmd, "w"); 1281a04a10f8SKris Kennaway if (f) { 1282e73e9afaSDag-Erling Smørgrav fprintf(f, "remove %s\n", 1283e73e9afaSDag-Erling Smørgrav s->auth_display); 1284af12a3e7SDag-Erling Smørgrav fprintf(f, "add %s %s %s\n", 1285af12a3e7SDag-Erling Smørgrav s->auth_display, s->auth_proto, 1286ca3176e7SBrian Feldman s->auth_data); 1287a04a10f8SKris Kennaway pclose(f); 1288c2d3a559SKris Kennaway } else { 1289c2d3a559SKris Kennaway fprintf(stderr, "Could not run %s\n", 1290c2d3a559SKris Kennaway cmd); 1291a04a10f8SKris Kennaway } 1292a04a10f8SKris Kennaway } 129319261079SEd Maste free(cmd); 129419261079SEd Maste free(user_rc); 1295a04a10f8SKris Kennaway } 1296ca3176e7SBrian Feldman 1297af12a3e7SDag-Erling Smørgrav static void 1298af12a3e7SDag-Erling Smørgrav do_nologin(struct passwd *pw) 1299af12a3e7SDag-Erling Smørgrav { 1300af12a3e7SDag-Erling Smørgrav FILE *f = NULL; 1301d93a896eSDag-Erling Smørgrav const char *nl; 1302d93a896eSDag-Erling Smørgrav char buf[1024], *def_nl = _PATH_NOLOGIN; 1303b15c8340SDag-Erling Smørgrav struct stat sb; 1304af12a3e7SDag-Erling Smørgrav 1305af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP 1306462c32cbSDag-Erling Smørgrav if (login_getcapbool(lc, "ignorenologin", 0) || pw->pw_uid == 0) 1307b15c8340SDag-Erling Smørgrav return; 1308b15c8340SDag-Erling Smørgrav nl = login_getcapstr(lc, "nologin", def_nl, def_nl); 1309af12a3e7SDag-Erling Smørgrav #else 1310b15c8340SDag-Erling Smørgrav if (pw->pw_uid == 0) 1311b15c8340SDag-Erling Smørgrav return; 1312b15c8340SDag-Erling Smørgrav nl = def_nl; 1313af12a3e7SDag-Erling Smørgrav #endif 1314d93a896eSDag-Erling Smørgrav if (stat(nl, &sb) == -1) 1315b15c8340SDag-Erling Smørgrav return; 1316b15c8340SDag-Erling Smørgrav 1317b15c8340SDag-Erling Smørgrav /* /etc/nologin exists. Print its contents if we can and exit. */ 1318b15c8340SDag-Erling Smørgrav logit("User %.100s not allowed because %s exists", pw->pw_name, nl); 1319b15c8340SDag-Erling Smørgrav if ((f = fopen(nl, "r")) != NULL) { 1320af12a3e7SDag-Erling Smørgrav while (fgets(buf, sizeof(buf), f)) 1321af12a3e7SDag-Erling Smørgrav fputs(buf, stderr); 1322af12a3e7SDag-Erling Smørgrav fclose(f); 1323af12a3e7SDag-Erling Smørgrav } 1324b15c8340SDag-Erling Smørgrav exit(254); 1325af12a3e7SDag-Erling Smørgrav } 1326af12a3e7SDag-Erling Smørgrav 1327d4af9e69SDag-Erling Smørgrav /* 1328d4af9e69SDag-Erling Smørgrav * Chroot into a directory after checking it for safety: all path components 1329d4af9e69SDag-Erling Smørgrav * must be root-owned directories with strict permissions. 1330d4af9e69SDag-Erling Smørgrav */ 1331d4af9e69SDag-Erling Smørgrav static void 1332d4af9e69SDag-Erling Smørgrav safely_chroot(const char *path, uid_t uid) 1333d4af9e69SDag-Erling Smørgrav { 1334d4af9e69SDag-Erling Smørgrav const char *cp; 1335bc5531deSDag-Erling Smørgrav char component[PATH_MAX]; 1336d4af9e69SDag-Erling Smørgrav struct stat st; 1337d4af9e69SDag-Erling Smørgrav 133819261079SEd Maste if (!path_absolute(path)) 1339d4af9e69SDag-Erling Smørgrav fatal("chroot path does not begin at root"); 1340d4af9e69SDag-Erling Smørgrav if (strlen(path) >= sizeof(component)) 1341d4af9e69SDag-Erling Smørgrav fatal("chroot path too long"); 1342d4af9e69SDag-Erling Smørgrav 1343d4af9e69SDag-Erling Smørgrav /* 1344d4af9e69SDag-Erling Smørgrav * Descend the path, checking that each component is a 1345d4af9e69SDag-Erling Smørgrav * root-owned directory with strict permissions. 1346d4af9e69SDag-Erling Smørgrav */ 1347d4af9e69SDag-Erling Smørgrav for (cp = path; cp != NULL;) { 1348d4af9e69SDag-Erling Smørgrav if ((cp = strchr(cp, '/')) == NULL) 1349d4af9e69SDag-Erling Smørgrav strlcpy(component, path, sizeof(component)); 1350d4af9e69SDag-Erling Smørgrav else { 1351d4af9e69SDag-Erling Smørgrav cp++; 1352d4af9e69SDag-Erling Smørgrav memcpy(component, path, cp - path); 1353d4af9e69SDag-Erling Smørgrav component[cp - path] = '\0'; 1354d4af9e69SDag-Erling Smørgrav } 1355d4af9e69SDag-Erling Smørgrav 135619261079SEd Maste debug3_f("checking '%s'", component); 1357d4af9e69SDag-Erling Smørgrav 1358d4af9e69SDag-Erling Smørgrav if (stat(component, &st) != 0) 135919261079SEd Maste fatal_f("stat(\"%s\"): %s", 1360d4af9e69SDag-Erling Smørgrav component, strerror(errno)); 1361d4af9e69SDag-Erling Smørgrav if (st.st_uid != 0 || (st.st_mode & 022) != 0) 1362d4af9e69SDag-Erling Smørgrav fatal("bad ownership or modes for chroot " 1363d4af9e69SDag-Erling Smørgrav "directory %s\"%s\"", 1364d4af9e69SDag-Erling Smørgrav cp == NULL ? "" : "component ", component); 1365d4af9e69SDag-Erling Smørgrav if (!S_ISDIR(st.st_mode)) 1366d4af9e69SDag-Erling Smørgrav fatal("chroot path %s\"%s\" is not a directory", 1367d4af9e69SDag-Erling Smørgrav cp == NULL ? "" : "component ", component); 1368d4af9e69SDag-Erling Smørgrav 1369d4af9e69SDag-Erling Smørgrav } 1370d4af9e69SDag-Erling Smørgrav 1371d4af9e69SDag-Erling Smørgrav if (chdir(path) == -1) 1372d4af9e69SDag-Erling Smørgrav fatal("Unable to chdir to chroot path \"%s\": " 1373d4af9e69SDag-Erling Smørgrav "%s", path, strerror(errno)); 1374d4af9e69SDag-Erling Smørgrav if (chroot(path) == -1) 1375d4af9e69SDag-Erling Smørgrav fatal("chroot(\"%s\"): %s", path, strerror(errno)); 1376d4af9e69SDag-Erling Smørgrav if (chdir("/") == -1) 137719261079SEd Maste fatal_f("chdir(/) after chroot: %s", strerror(errno)); 1378d4af9e69SDag-Erling Smørgrav verbose("Changed root directory to \"%s\"", path); 1379d4af9e69SDag-Erling Smørgrav } 1380d4af9e69SDag-Erling Smørgrav 1381af12a3e7SDag-Erling Smørgrav /* Set login name, uid, gid, and groups. */ 1382989dd127SDag-Erling Smørgrav void 138380628bacSDag-Erling Smørgrav do_setusercontext(struct passwd *pw) 1384af12a3e7SDag-Erling Smørgrav { 1385190cef3dSDag-Erling Smørgrav char uidstr[32], *chroot_path, *tmp; 1386d4af9e69SDag-Erling Smørgrav 13874a421b63SDag-Erling Smørgrav platform_setusercontext(pw); 1388d4af9e69SDag-Erling Smørgrav 13894a421b63SDag-Erling Smørgrav if (platform_privileged_uidswap()) { 1390989dd127SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP 1391989dd127SDag-Erling Smørgrav if (setusercontext(lc, pw, pw->pw_uid, 1392d4af9e69SDag-Erling Smørgrav (LOGIN_SETALL & ~(LOGIN_SETENV|LOGIN_SETPATH|LOGIN_SETUSER))) < 0) { 1393989dd127SDag-Erling Smørgrav perror("unable to set user context"); 1394989dd127SDag-Erling Smørgrav exit(1); 1395989dd127SDag-Erling Smørgrav } 1396989dd127SDag-Erling Smørgrav #else 1397af12a3e7SDag-Erling Smørgrav if (setlogin(pw->pw_name) < 0) 1398af12a3e7SDag-Erling Smørgrav error("setlogin failed: %s", strerror(errno)); 1399af12a3e7SDag-Erling Smørgrav if (setgid(pw->pw_gid) < 0) { 1400af12a3e7SDag-Erling Smørgrav perror("setgid"); 1401af12a3e7SDag-Erling Smørgrav exit(1); 1402af12a3e7SDag-Erling Smørgrav } 1403af12a3e7SDag-Erling Smørgrav /* Initialize the group list. */ 1404af12a3e7SDag-Erling Smørgrav if (initgroups(pw->pw_name, pw->pw_gid) < 0) { 1405af12a3e7SDag-Erling Smørgrav perror("initgroups"); 1406af12a3e7SDag-Erling Smørgrav exit(1); 1407af12a3e7SDag-Erling Smørgrav } 1408af12a3e7SDag-Erling Smørgrav endgrent(); 1409d4af9e69SDag-Erling Smørgrav #endif 1410b15c8340SDag-Erling Smørgrav 14114a421b63SDag-Erling Smørgrav platform_setusercontext_post_groups(pw); 14128ad9b54aSDag-Erling Smørgrav 1413acc1a9efSDag-Erling Smørgrav if (!in_chroot && options.chroot_directory != NULL && 1414d4af9e69SDag-Erling Smørgrav strcasecmp(options.chroot_directory, "none") != 0) { 1415d4af9e69SDag-Erling Smørgrav tmp = tilde_expand_filename(options.chroot_directory, 1416d4af9e69SDag-Erling Smørgrav pw->pw_uid); 1417190cef3dSDag-Erling Smørgrav snprintf(uidstr, sizeof(uidstr), "%llu", 1418190cef3dSDag-Erling Smørgrav (unsigned long long)pw->pw_uid); 1419d4af9e69SDag-Erling Smørgrav chroot_path = percent_expand(tmp, "h", pw->pw_dir, 1420190cef3dSDag-Erling Smørgrav "u", pw->pw_name, "U", uidstr, (char *)NULL); 1421d4af9e69SDag-Erling Smørgrav safely_chroot(chroot_path, pw->pw_uid); 1422d4af9e69SDag-Erling Smørgrav free(tmp); 1423d4af9e69SDag-Erling Smørgrav free(chroot_path); 1424e4a9863fSDag-Erling Smørgrav /* Make sure we don't attempt to chroot again */ 1425e4a9863fSDag-Erling Smørgrav free(options.chroot_directory); 1426e4a9863fSDag-Erling Smørgrav options.chroot_directory = NULL; 1427acc1a9efSDag-Erling Smørgrav in_chroot = 1; 1428d4af9e69SDag-Erling Smørgrav } 1429d4af9e69SDag-Erling Smørgrav 1430d4af9e69SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP 1431d4af9e69SDag-Erling Smørgrav if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUSER) < 0) { 1432d4af9e69SDag-Erling Smørgrav perror("unable to set user context (setuser)"); 1433d4af9e69SDag-Erling Smørgrav exit(1); 1434d4af9e69SDag-Erling Smørgrav } 14352ec88e9dSDag-Erling Smørgrav /* 14362ec88e9dSDag-Erling Smørgrav * FreeBSD's setusercontext() will not apply the user's 14372ec88e9dSDag-Erling Smørgrav * own umask setting unless running with the user's UID. 14382ec88e9dSDag-Erling Smørgrav */ 14396888a9beSDag-Erling Smørgrav (void) setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUMASK); 1440d4af9e69SDag-Erling Smørgrav #else 1441f7167e0eSDag-Erling Smørgrav # ifdef USE_LIBIAF 1442acc1a9efSDag-Erling Smørgrav /* 1443acc1a9efSDag-Erling Smørgrav * In a chroot environment, the set_id() will always fail; 1444acc1a9efSDag-Erling Smørgrav * typically because of the lack of necessary authentication 1445acc1a9efSDag-Erling Smørgrav * services and runtime such as ./usr/lib/libiaf.so, 1446acc1a9efSDag-Erling Smørgrav * ./usr/lib/libpam.so.1, and ./etc/passwd We skip it in the 1447acc1a9efSDag-Erling Smørgrav * internal sftp chroot case. We'll lose auditing and ACLs but 1448acc1a9efSDag-Erling Smørgrav * permanently_set_uid will take care of the rest. 1449a0ee8cc6SDag-Erling Smørgrav */ 1450acc1a9efSDag-Erling Smørgrav if (!in_chroot && set_id(pw->pw_name) != 0) 1451f7167e0eSDag-Erling Smørgrav fatal("set_id(%s) Failed", pw->pw_name); 1452f7167e0eSDag-Erling Smørgrav # endif /* USE_LIBIAF */ 1453af12a3e7SDag-Erling Smørgrav /* Permanently switch to the desired uid. */ 1454af12a3e7SDag-Erling Smørgrav permanently_set_uid(pw); 1455989dd127SDag-Erling Smørgrav #endif 1456e4a9863fSDag-Erling Smørgrav } else if (options.chroot_directory != NULL && 1457e4a9863fSDag-Erling Smørgrav strcasecmp(options.chroot_directory, "none") != 0) { 1458e4a9863fSDag-Erling Smørgrav fatal("server lacks privileges to chroot to ChrootDirectory"); 1459af12a3e7SDag-Erling Smørgrav } 1460e73e9afaSDag-Erling Smørgrav 1461af12a3e7SDag-Erling Smørgrav if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) 1462af12a3e7SDag-Erling Smørgrav fatal("Failed to set uids to %u.", (u_int) pw->pw_uid); 146380628bacSDag-Erling Smørgrav } 146480628bacSDag-Erling Smørgrav 146580628bacSDag-Erling Smørgrav static void 14661ec0d754SDag-Erling Smørgrav do_pwchange(Session *s) 14671ec0d754SDag-Erling Smørgrav { 146821e764dfSDag-Erling Smørgrav fflush(NULL); 14691ec0d754SDag-Erling Smørgrav fprintf(stderr, "WARNING: Your password has expired.\n"); 14701ec0d754SDag-Erling Smørgrav if (s->ttyfd != -1) { 14711ec0d754SDag-Erling Smørgrav fprintf(stderr, 14721ec0d754SDag-Erling Smørgrav "You must change your password now and login again!\n"); 1473e146993eSDag-Erling Smørgrav #ifdef WITH_SELINUX 1474e146993eSDag-Erling Smørgrav setexeccon(NULL); 1475e146993eSDag-Erling Smørgrav #endif 1476aa49c926SDag-Erling Smørgrav #ifdef PASSWD_NEEDS_USERNAME 1477aa49c926SDag-Erling Smørgrav execl(_PATH_PASSWD_PROG, "passwd", s->pw->pw_name, 1478aa49c926SDag-Erling Smørgrav (char *)NULL); 1479aa49c926SDag-Erling Smørgrav #else 14801ec0d754SDag-Erling Smørgrav execl(_PATH_PASSWD_PROG, "passwd", (char *)NULL); 1481aa49c926SDag-Erling Smørgrav #endif 14821ec0d754SDag-Erling Smørgrav perror("passwd"); 14831ec0d754SDag-Erling Smørgrav } else { 14841ec0d754SDag-Erling Smørgrav fprintf(stderr, 14851ec0d754SDag-Erling Smørgrav "Password change required but no TTY available.\n"); 14861ec0d754SDag-Erling Smørgrav } 14871ec0d754SDag-Erling Smørgrav exit(1); 14881ec0d754SDag-Erling Smørgrav } 14891ec0d754SDag-Erling Smørgrav 14901ec0d754SDag-Erling Smørgrav static void 14914f52dfbbSDag-Erling Smørgrav child_close_fds(struct ssh *ssh) 14921ec0d754SDag-Erling Smørgrav { 1493bc5531deSDag-Erling Smørgrav extern int auth_sock; 1494e4a9863fSDag-Erling Smørgrav 1495bc5531deSDag-Erling Smørgrav if (auth_sock != -1) { 1496bc5531deSDag-Erling Smørgrav close(auth_sock); 1497bc5531deSDag-Erling Smørgrav auth_sock = -1; 1498e4a9863fSDag-Erling Smørgrav } 1499e4a9863fSDag-Erling Smørgrav 150019261079SEd Maste if (ssh_packet_get_connection_in(ssh) == 150119261079SEd Maste ssh_packet_get_connection_out(ssh)) 150219261079SEd Maste close(ssh_packet_get_connection_in(ssh)); 15031ec0d754SDag-Erling Smørgrav else { 150419261079SEd Maste close(ssh_packet_get_connection_in(ssh)); 150519261079SEd Maste close(ssh_packet_get_connection_out(ssh)); 15061ec0d754SDag-Erling Smørgrav } 15071ec0d754SDag-Erling Smørgrav /* 15081ec0d754SDag-Erling Smørgrav * Close all descriptors related to channels. They will still remain 15091ec0d754SDag-Erling Smørgrav * open in the parent. 15101ec0d754SDag-Erling Smørgrav */ 15111ec0d754SDag-Erling Smørgrav /* XXX better use close-on-exec? -markus */ 15124f52dfbbSDag-Erling Smørgrav channel_close_all(ssh); 15131ec0d754SDag-Erling Smørgrav 15141ec0d754SDag-Erling Smørgrav /* 15151ec0d754SDag-Erling Smørgrav * Close any extra file descriptors. Note that there may still be 15161ec0d754SDag-Erling Smørgrav * descriptors left by system functions. They will be closed later. 15171ec0d754SDag-Erling Smørgrav */ 15181ec0d754SDag-Erling Smørgrav endpwent(); 15191ec0d754SDag-Erling Smørgrav 152019261079SEd Maste /* Stop directing logs to a high-numbered fd before we close it */ 152119261079SEd Maste log_redirect_stderr_to(NULL); 152219261079SEd Maste 15231ec0d754SDag-Erling Smørgrav /* 1524b74df5b2SDag-Erling Smørgrav * Close any extra open file descriptors so that we don't have them 15251ec0d754SDag-Erling Smørgrav * hanging around in clients. Note that we want to do this after 15261ec0d754SDag-Erling Smørgrav * initgroups, because at least on Solaris 2.3 it leaves file 15271ec0d754SDag-Erling Smørgrav * descriptors open. 15281ec0d754SDag-Erling Smørgrav */ 15294a421b63SDag-Erling Smørgrav closefrom(STDERR_FILENO + 1); 15301ec0d754SDag-Erling Smørgrav } 15311ec0d754SDag-Erling Smørgrav 1532af12a3e7SDag-Erling Smørgrav /* 1533af12a3e7SDag-Erling Smørgrav * Performs common processing for the child, such as setting up the 1534af12a3e7SDag-Erling Smørgrav * environment, closing extra file descriptors, setting the user and group 1535af12a3e7SDag-Erling Smørgrav * ids, and executing the command or shell. 1536af12a3e7SDag-Erling Smørgrav */ 1537d4af9e69SDag-Erling Smørgrav #define ARGV_MAX 10 1538af12a3e7SDag-Erling Smørgrav void 15394f52dfbbSDag-Erling Smørgrav do_child(struct ssh *ssh, Session *s, const char *command) 1540af12a3e7SDag-Erling Smørgrav { 1541af12a3e7SDag-Erling Smørgrav extern char **environ; 154219261079SEd Maste char **env, *argv[ARGV_MAX], remote_id[512]; 1543ca86bcf2SDag-Erling Smørgrav const char *shell, *shell0; 1544af12a3e7SDag-Erling Smørgrav struct passwd *pw = s->pw; 1545d4af9e69SDag-Erling Smørgrav int r = 0; 1546af12a3e7SDag-Erling Smørgrav 154719261079SEd Maste sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id)); 154819261079SEd Maste 1549af12a3e7SDag-Erling Smørgrav /* remove hostkey from the child's memory */ 1550af12a3e7SDag-Erling Smørgrav destroy_sensitive_data(); 155119261079SEd Maste ssh_packet_clear_keys(ssh); 1552af12a3e7SDag-Erling Smørgrav 15531ec0d754SDag-Erling Smørgrav /* Force a password change */ 15541ec0d754SDag-Erling Smørgrav if (s->authctxt->force_pwchange) { 15551ec0d754SDag-Erling Smørgrav do_setusercontext(pw); 15564f52dfbbSDag-Erling Smørgrav child_close_fds(ssh); 15571ec0d754SDag-Erling Smørgrav do_pwchange(s); 15581ec0d754SDag-Erling Smørgrav exit(1); 15591ec0d754SDag-Erling Smørgrav } 15601ec0d754SDag-Erling Smørgrav 1561af12a3e7SDag-Erling Smørgrav /* 1562af12a3e7SDag-Erling Smørgrav * Login(1) does this as well, and it needs uid 0 for the "-h" 1563af12a3e7SDag-Erling Smørgrav * switch, so we let login(1) to this for us. 1564af12a3e7SDag-Erling Smørgrav */ 1565989dd127SDag-Erling Smørgrav #ifdef HAVE_OSF_SIA 1566e73e9afaSDag-Erling Smørgrav session_setup_sia(pw, s->ttyfd == -1 ? NULL : s->tty); 1567989dd127SDag-Erling Smørgrav if (!check_quietlogin(s, command)) 1568989dd127SDag-Erling Smørgrav do_motd(); 1569989dd127SDag-Erling Smørgrav #else /* HAVE_OSF_SIA */ 1570b74df5b2SDag-Erling Smørgrav /* When PAM is enabled we rely on it to do the nologin check */ 1571b74df5b2SDag-Erling Smørgrav if (!options.use_pam) 1572af12a3e7SDag-Erling Smørgrav do_nologin(pw); 1573989dd127SDag-Erling Smørgrav do_setusercontext(pw); 157421e764dfSDag-Erling Smørgrav /* 157521e764dfSDag-Erling Smørgrav * PAM session modules in do_setusercontext may have 157621e764dfSDag-Erling Smørgrav * generated messages, so if this in an interactive 157721e764dfSDag-Erling Smørgrav * login then display them too. 157821e764dfSDag-Erling Smørgrav */ 1579aa49c926SDag-Erling Smørgrav if (!check_quietlogin(s, command)) 158021e764dfSDag-Erling Smørgrav display_loginmsg(); 1581989dd127SDag-Erling Smørgrav #endif /* HAVE_OSF_SIA */ 1582af12a3e7SDag-Erling Smørgrav 1583aa49c926SDag-Erling Smørgrav #ifdef USE_PAM 1584ca86bcf2SDag-Erling Smørgrav if (options.use_pam && !is_pam_session_open()) { 1585aa49c926SDag-Erling Smørgrav debug3("PAM session not opened, exiting"); 1586aa49c926SDag-Erling Smørgrav display_loginmsg(); 1587aa49c926SDag-Erling Smørgrav exit(254); 1588aa49c926SDag-Erling Smørgrav } 1589aa49c926SDag-Erling Smørgrav #endif 1590aa49c926SDag-Erling Smørgrav 1591af12a3e7SDag-Erling Smørgrav /* 1592af12a3e7SDag-Erling Smørgrav * Get the shell from the password data. An empty shell field is 1593af12a3e7SDag-Erling Smørgrav * legal, and means /bin/sh. 1594af12a3e7SDag-Erling Smørgrav */ 1595af12a3e7SDag-Erling Smørgrav shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; 1596e73e9afaSDag-Erling Smørgrav 1597e73e9afaSDag-Erling Smørgrav /* 1598e73e9afaSDag-Erling Smørgrav * Make sure $SHELL points to the shell from the password file, 1599e73e9afaSDag-Erling Smørgrav * even if shell is overridden from login.conf 1600e73e9afaSDag-Erling Smørgrav */ 16014f52dfbbSDag-Erling Smørgrav env = do_setup_env(ssh, s, shell); 1602e73e9afaSDag-Erling Smørgrav 1603af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP 1604af12a3e7SDag-Erling Smørgrav shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell); 1605af12a3e7SDag-Erling Smørgrav #endif 1606af12a3e7SDag-Erling Smørgrav 1607af12a3e7SDag-Erling Smørgrav /* 1608af12a3e7SDag-Erling Smørgrav * Close the connection descriptors; note that this is the child, and 1609af12a3e7SDag-Erling Smørgrav * the server will still have the socket open, and it is important 1610af12a3e7SDag-Erling Smørgrav * that we do not shutdown it. Note that the descriptors cannot be 1611af12a3e7SDag-Erling Smørgrav * closed before building the environment, as we call 1612076ad2f8SDag-Erling Smørgrav * ssh_remote_ipaddr there. 1613af12a3e7SDag-Erling Smørgrav */ 16144f52dfbbSDag-Erling Smørgrav child_close_fds(ssh); 1615af12a3e7SDag-Erling Smørgrav 1616af12a3e7SDag-Erling Smørgrav /* 1617af12a3e7SDag-Erling Smørgrav * Must take new environment into use so that .ssh/rc, 1618af12a3e7SDag-Erling Smørgrav * /etc/ssh/sshrc and xauth are run in the proper environment. 1619af12a3e7SDag-Erling Smørgrav */ 1620af12a3e7SDag-Erling Smørgrav environ = env; 1621af12a3e7SDag-Erling Smørgrav 16221ec0d754SDag-Erling Smørgrav #if defined(KRB5) && defined(USE_AFS) 16231ec0d754SDag-Erling Smørgrav /* 16241ec0d754SDag-Erling Smørgrav * At this point, we check to see if AFS is active and if we have 16251ec0d754SDag-Erling Smørgrav * a valid Kerberos 5 TGT. If so, it seems like a good idea to see 16261ec0d754SDag-Erling Smørgrav * if we can (and need to) extend the ticket into an AFS token. If 16271ec0d754SDag-Erling Smørgrav * we don't do this, we run into potential problems if the user's 16281ec0d754SDag-Erling Smørgrav * home directory is in AFS and it's not world-readable. 16291ec0d754SDag-Erling Smørgrav */ 16301ec0d754SDag-Erling Smørgrav 16311ec0d754SDag-Erling Smørgrav if (options.kerberos_get_afs_token && k_hasafs() && 16321ec0d754SDag-Erling Smørgrav (s->authctxt->krb5_ctx != NULL)) { 16331ec0d754SDag-Erling Smørgrav char cell[64]; 16341ec0d754SDag-Erling Smørgrav 16351ec0d754SDag-Erling Smørgrav debug("Getting AFS token"); 16361ec0d754SDag-Erling Smørgrav 16371ec0d754SDag-Erling Smørgrav k_setpag(); 16381ec0d754SDag-Erling Smørgrav 16391ec0d754SDag-Erling Smørgrav if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0) 16401ec0d754SDag-Erling Smørgrav krb5_afslog(s->authctxt->krb5_ctx, 16411ec0d754SDag-Erling Smørgrav s->authctxt->krb5_fwd_ccache, cell, NULL); 16421ec0d754SDag-Erling Smørgrav 16431ec0d754SDag-Erling Smørgrav krb5_afslog_home(s->authctxt->krb5_ctx, 16441ec0d754SDag-Erling Smørgrav s->authctxt->krb5_fwd_ccache, NULL, NULL, pw->pw_dir); 16451ec0d754SDag-Erling Smørgrav } 16461ec0d754SDag-Erling Smørgrav #endif 16471ec0d754SDag-Erling Smørgrav 1648b74df5b2SDag-Erling Smørgrav /* Change current directory to the user's home directory. */ 164919261079SEd Maste if (chdir(pw->pw_dir) == -1) { 1650d4af9e69SDag-Erling Smørgrav /* Suppress missing homedir warning for chroot case */ 1651af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP 1652d4af9e69SDag-Erling Smørgrav r = login_getcapbool(lc, "requirehome", 0); 1653af12a3e7SDag-Erling Smørgrav #endif 1654acc1a9efSDag-Erling Smørgrav if (r || !in_chroot) { 1655d4af9e69SDag-Erling Smørgrav fprintf(stderr, "Could not chdir to home " 1656d4af9e69SDag-Erling Smørgrav "directory %s: %s\n", pw->pw_dir, 1657d4af9e69SDag-Erling Smørgrav strerror(errno)); 1658acc1a9efSDag-Erling Smørgrav } 1659d4af9e69SDag-Erling Smørgrav if (r) 1660d4af9e69SDag-Erling Smørgrav exit(1); 1661af12a3e7SDag-Erling Smørgrav } 1662af12a3e7SDag-Erling Smørgrav 1663d4af9e69SDag-Erling Smørgrav closefrom(STDERR_FILENO + 1); 1664d4af9e69SDag-Erling Smørgrav 166547dd1d1bSDag-Erling Smørgrav do_rc_files(ssh, s, shell); 1666af12a3e7SDag-Erling Smørgrav 1667ca3176e7SBrian Feldman /* restore SIGPIPE for child */ 166819261079SEd Maste ssh_signal(SIGPIPE, SIG_DFL); 1669ca3176e7SBrian Feldman 1670b15c8340SDag-Erling Smørgrav if (s->is_subsystem == SUBSYSTEM_INT_SFTP_ERROR) { 167119261079SEd Maste error("Connection from %s: refusing non-sftp session", 167219261079SEd Maste remote_id); 1673b15c8340SDag-Erling Smørgrav printf("This service allows sftp connections only.\n"); 1674b15c8340SDag-Erling Smørgrav fflush(NULL); 1675b15c8340SDag-Erling Smørgrav exit(1); 1676b15c8340SDag-Erling Smørgrav } else if (s->is_subsystem == SUBSYSTEM_INT_SFTP) { 1677d4af9e69SDag-Erling Smørgrav extern int optind, optreset; 1678d4af9e69SDag-Erling Smørgrav int i; 1679d4af9e69SDag-Erling Smørgrav char *p, *args; 1680d4af9e69SDag-Erling Smørgrav 16817aee6ffeSDag-Erling Smørgrav setproctitle("%s@%s", s->pw->pw_name, INTERNAL_SFTP_NAME); 1682cce7d346SDag-Erling Smørgrav args = xstrdup(command ? command : "sftp-server"); 1683d4af9e69SDag-Erling Smørgrav for (i = 0, (p = strtok(args, " ")); p; (p = strtok(NULL, " "))) 1684d4af9e69SDag-Erling Smørgrav if (i < ARGV_MAX - 1) 1685d4af9e69SDag-Erling Smørgrav argv[i++] = p; 1686d4af9e69SDag-Erling Smørgrav argv[i] = NULL; 1687d4af9e69SDag-Erling Smørgrav optind = optreset = 1; 1688d4af9e69SDag-Erling Smørgrav __progname = argv[0]; 1689b15c8340SDag-Erling Smørgrav #ifdef WITH_SELINUX 1690b15c8340SDag-Erling Smørgrav ssh_selinux_change_context("sftpd_t"); 1691b15c8340SDag-Erling Smørgrav #endif 1692d4af9e69SDag-Erling Smørgrav exit(sftp_server_main(i, argv, s->pw)); 1693d4af9e69SDag-Erling Smørgrav } 1694d4af9e69SDag-Erling Smørgrav 1695b15c8340SDag-Erling Smørgrav fflush(NULL); 1696b15c8340SDag-Erling Smørgrav 1697af12a3e7SDag-Erling Smørgrav /* Get the last component of the shell name. */ 1698af12a3e7SDag-Erling Smørgrav if ((shell0 = strrchr(shell, '/')) != NULL) 1699af12a3e7SDag-Erling Smørgrav shell0++; 1700af12a3e7SDag-Erling Smørgrav else 1701af12a3e7SDag-Erling Smørgrav shell0 = shell; 1702af12a3e7SDag-Erling Smørgrav 1703a04a10f8SKris Kennaway /* 1704a04a10f8SKris Kennaway * If we have no command, execute the shell. In this case, the shell 1705a04a10f8SKris Kennaway * name to be passed in argv[0] is preceded by '-' to indicate that 1706a04a10f8SKris Kennaway * this is a login shell. 1707a04a10f8SKris Kennaway */ 1708a04a10f8SKris Kennaway if (!command) { 1709af12a3e7SDag-Erling Smørgrav char argv0[256]; 1710a04a10f8SKris Kennaway 1711a04a10f8SKris Kennaway /* Start the shell. Set initial character to '-'. */ 1712af12a3e7SDag-Erling Smørgrav argv0[0] = '-'; 1713af12a3e7SDag-Erling Smørgrav 1714af12a3e7SDag-Erling Smørgrav if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1) 1715af12a3e7SDag-Erling Smørgrav >= sizeof(argv0) - 1) { 1716af12a3e7SDag-Erling Smørgrav errno = EINVAL; 1717af12a3e7SDag-Erling Smørgrav perror(shell); 1718af12a3e7SDag-Erling Smørgrav exit(1); 1719af12a3e7SDag-Erling Smørgrav } 1720a04a10f8SKris Kennaway 1721a04a10f8SKris Kennaway /* Execute the shell. */ 1722af12a3e7SDag-Erling Smørgrav argv[0] = argv0; 1723a04a10f8SKris Kennaway argv[1] = NULL; 1724a04a10f8SKris Kennaway execve(shell, argv, env); 1725a04a10f8SKris Kennaway 1726a04a10f8SKris Kennaway /* Executing the shell failed. */ 1727a04a10f8SKris Kennaway perror(shell); 1728a04a10f8SKris Kennaway exit(1); 1729a04a10f8SKris Kennaway } 1730a04a10f8SKris Kennaway /* 1731a04a10f8SKris Kennaway * Execute the command using the user's shell. This uses the -c 1732a04a10f8SKris Kennaway * option to execute the command. 1733a04a10f8SKris Kennaway */ 1734af12a3e7SDag-Erling Smørgrav argv[0] = (char *) shell0; 1735a04a10f8SKris Kennaway argv[1] = "-c"; 1736a04a10f8SKris Kennaway argv[2] = (char *) command; 1737a04a10f8SKris Kennaway argv[3] = NULL; 1738a04a10f8SKris Kennaway execve(shell, argv, env); 1739a04a10f8SKris Kennaway perror(shell); 1740a04a10f8SKris Kennaway exit(1); 1741a04a10f8SKris Kennaway } 1742a04a10f8SKris Kennaway 1743d4af9e69SDag-Erling Smørgrav void 1744d4af9e69SDag-Erling Smørgrav session_unused(int id) 1745d4af9e69SDag-Erling Smørgrav { 174619261079SEd Maste debug3_f("session id %d unused", id); 1747d4af9e69SDag-Erling Smørgrav if (id >= options.max_sessions || 1748d4af9e69SDag-Erling Smørgrav id >= sessions_nalloc) { 174919261079SEd Maste fatal_f("insane session id %d (max %d nalloc %d)", 175019261079SEd Maste id, options.max_sessions, sessions_nalloc); 1751d4af9e69SDag-Erling Smørgrav } 1752b83788ffSDag-Erling Smørgrav memset(&sessions[id], 0, sizeof(*sessions)); 1753d4af9e69SDag-Erling Smørgrav sessions[id].self = id; 1754d4af9e69SDag-Erling Smørgrav sessions[id].used = 0; 1755d4af9e69SDag-Erling Smørgrav sessions[id].chanid = -1; 1756d4af9e69SDag-Erling Smørgrav sessions[id].ptyfd = -1; 1757d4af9e69SDag-Erling Smørgrav sessions[id].ttyfd = -1; 1758d4af9e69SDag-Erling Smørgrav sessions[id].ptymaster = -1; 1759d4af9e69SDag-Erling Smørgrav sessions[id].x11_chanids = NULL; 1760d4af9e69SDag-Erling Smørgrav sessions[id].next_unused = sessions_first_unused; 1761d4af9e69SDag-Erling Smørgrav sessions_first_unused = id; 1762d4af9e69SDag-Erling Smørgrav } 1763d4af9e69SDag-Erling Smørgrav 1764a04a10f8SKris Kennaway Session * 1765a04a10f8SKris Kennaway session_new(void) 1766a04a10f8SKris Kennaway { 1767d4af9e69SDag-Erling Smørgrav Session *s, *tmp; 1768d4af9e69SDag-Erling Smørgrav 1769d4af9e69SDag-Erling Smørgrav if (sessions_first_unused == -1) { 1770d4af9e69SDag-Erling Smørgrav if (sessions_nalloc >= options.max_sessions) 1771a04a10f8SKris Kennaway return NULL; 177219261079SEd Maste debug2_f("allocate (allocated %d max %d)", 177319261079SEd Maste sessions_nalloc, options.max_sessions); 17744f52dfbbSDag-Erling Smørgrav tmp = xrecallocarray(sessions, sessions_nalloc, 17754f52dfbbSDag-Erling Smørgrav sessions_nalloc + 1, sizeof(*sessions)); 1776d4af9e69SDag-Erling Smørgrav if (tmp == NULL) { 177719261079SEd Maste error_f("cannot allocate %d sessions", 177819261079SEd Maste sessions_nalloc + 1); 1779d4af9e69SDag-Erling Smørgrav return NULL; 1780d4af9e69SDag-Erling Smørgrav } 1781d4af9e69SDag-Erling Smørgrav sessions = tmp; 1782d4af9e69SDag-Erling Smørgrav session_unused(sessions_nalloc++); 1783d4af9e69SDag-Erling Smørgrav } 1784d4af9e69SDag-Erling Smørgrav 1785d4af9e69SDag-Erling Smørgrav if (sessions_first_unused >= sessions_nalloc || 1786d4af9e69SDag-Erling Smørgrav sessions_first_unused < 0) { 178719261079SEd Maste fatal_f("insane first_unused %d max %d nalloc %d", 178819261079SEd Maste sessions_first_unused, options.max_sessions, 1789d4af9e69SDag-Erling Smørgrav sessions_nalloc); 1790d4af9e69SDag-Erling Smørgrav } 1791d4af9e69SDag-Erling Smørgrav 1792d4af9e69SDag-Erling Smørgrav s = &sessions[sessions_first_unused]; 179319261079SEd Maste if (s->used) 179419261079SEd Maste fatal_f("session %d already used", sessions_first_unused); 1795d4af9e69SDag-Erling Smørgrav sessions_first_unused = s->next_unused; 1796d4af9e69SDag-Erling Smørgrav s->used = 1; 1797d4af9e69SDag-Erling Smørgrav s->next_unused = -1; 1798d4af9e69SDag-Erling Smørgrav debug("session_new: session %d", s->self); 1799d4af9e69SDag-Erling Smørgrav 1800d4af9e69SDag-Erling Smørgrav return s; 1801a04a10f8SKris Kennaway } 1802a04a10f8SKris Kennaway 1803af12a3e7SDag-Erling Smørgrav static void 1804a04a10f8SKris Kennaway session_dump(void) 1805a04a10f8SKris Kennaway { 1806a04a10f8SKris Kennaway int i; 1807d4af9e69SDag-Erling Smørgrav for (i = 0; i < sessions_nalloc; i++) { 1808a04a10f8SKris Kennaway Session *s = &sessions[i]; 1809d4af9e69SDag-Erling Smørgrav 181019261079SEd Maste debug("dump: used %d next_unused %d session %d " 1811d4af9e69SDag-Erling Smørgrav "channel %d pid %ld", 1812a04a10f8SKris Kennaway s->used, 1813d4af9e69SDag-Erling Smørgrav s->next_unused, 1814a04a10f8SKris Kennaway s->self, 1815a04a10f8SKris Kennaway s->chanid, 181680628bacSDag-Erling Smørgrav (long)s->pid); 1817a04a10f8SKris Kennaway } 1818a04a10f8SKris Kennaway } 1819a04a10f8SKris Kennaway 1820a04a10f8SKris Kennaway int 1821af12a3e7SDag-Erling Smørgrav session_open(Authctxt *authctxt, int chanid) 1822a04a10f8SKris Kennaway { 1823a04a10f8SKris Kennaway Session *s = session_new(); 1824a04a10f8SKris Kennaway debug("session_open: channel %d", chanid); 1825a04a10f8SKris Kennaway if (s == NULL) { 1826a04a10f8SKris Kennaway error("no more sessions"); 1827a04a10f8SKris Kennaway return 0; 1828a04a10f8SKris Kennaway } 1829af12a3e7SDag-Erling Smørgrav s->authctxt = authctxt; 1830af12a3e7SDag-Erling Smørgrav s->pw = authctxt->pw; 18311ec0d754SDag-Erling Smørgrav if (s->pw == NULL || !authctxt->valid) 1832ca3176e7SBrian Feldman fatal("no user for session %d", s->self); 1833a04a10f8SKris Kennaway debug("session_open: session %d: link with channel %d", s->self, chanid); 1834a04a10f8SKris Kennaway s->chanid = chanid; 1835a04a10f8SKris Kennaway return 1; 1836a04a10f8SKris Kennaway } 1837a04a10f8SKris Kennaway 183880628bacSDag-Erling Smørgrav Session * 183980628bacSDag-Erling Smørgrav session_by_tty(char *tty) 184080628bacSDag-Erling Smørgrav { 184180628bacSDag-Erling Smørgrav int i; 1842d4af9e69SDag-Erling Smørgrav for (i = 0; i < sessions_nalloc; i++) { 184380628bacSDag-Erling Smørgrav Session *s = &sessions[i]; 184480628bacSDag-Erling Smørgrav if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) { 184580628bacSDag-Erling Smørgrav debug("session_by_tty: session %d tty %s", i, tty); 184680628bacSDag-Erling Smørgrav return s; 184780628bacSDag-Erling Smørgrav } 184880628bacSDag-Erling Smørgrav } 184980628bacSDag-Erling Smørgrav debug("session_by_tty: unknown tty %.100s", tty); 185080628bacSDag-Erling Smørgrav session_dump(); 185180628bacSDag-Erling Smørgrav return NULL; 185280628bacSDag-Erling Smørgrav } 185380628bacSDag-Erling Smørgrav 1854af12a3e7SDag-Erling Smørgrav static Session * 1855a04a10f8SKris Kennaway session_by_channel(int id) 1856a04a10f8SKris Kennaway { 1857a04a10f8SKris Kennaway int i; 1858d4af9e69SDag-Erling Smørgrav for (i = 0; i < sessions_nalloc; i++) { 1859a04a10f8SKris Kennaway Session *s = &sessions[i]; 1860a04a10f8SKris Kennaway if (s->used && s->chanid == id) { 1861d4af9e69SDag-Erling Smørgrav debug("session_by_channel: session %d channel %d", 1862d4af9e69SDag-Erling Smørgrav i, id); 1863a04a10f8SKris Kennaway return s; 1864a04a10f8SKris Kennaway } 1865a04a10f8SKris Kennaway } 1866a04a10f8SKris Kennaway debug("session_by_channel: unknown channel %d", id); 1867a04a10f8SKris Kennaway session_dump(); 1868a04a10f8SKris Kennaway return NULL; 1869a04a10f8SKris Kennaway } 1870a04a10f8SKris Kennaway 1871af12a3e7SDag-Erling Smørgrav static Session * 1872d4ecd108SDag-Erling Smørgrav session_by_x11_channel(int id) 1873d4ecd108SDag-Erling Smørgrav { 1874d4ecd108SDag-Erling Smørgrav int i, j; 1875d4ecd108SDag-Erling Smørgrav 1876d4af9e69SDag-Erling Smørgrav for (i = 0; i < sessions_nalloc; i++) { 1877d4ecd108SDag-Erling Smørgrav Session *s = &sessions[i]; 1878d4ecd108SDag-Erling Smørgrav 1879d4ecd108SDag-Erling Smørgrav if (s->x11_chanids == NULL || !s->used) 1880d4ecd108SDag-Erling Smørgrav continue; 1881d4ecd108SDag-Erling Smørgrav for (j = 0; s->x11_chanids[j] != -1; j++) { 1882d4ecd108SDag-Erling Smørgrav if (s->x11_chanids[j] == id) { 1883d4ecd108SDag-Erling Smørgrav debug("session_by_x11_channel: session %d " 1884d4ecd108SDag-Erling Smørgrav "channel %d", s->self, id); 1885d4ecd108SDag-Erling Smørgrav return s; 1886d4ecd108SDag-Erling Smørgrav } 1887d4ecd108SDag-Erling Smørgrav } 1888d4ecd108SDag-Erling Smørgrav } 1889d4ecd108SDag-Erling Smørgrav debug("session_by_x11_channel: unknown channel %d", id); 1890d4ecd108SDag-Erling Smørgrav session_dump(); 1891d4ecd108SDag-Erling Smørgrav return NULL; 1892d4ecd108SDag-Erling Smørgrav } 1893d4ecd108SDag-Erling Smørgrav 1894d4ecd108SDag-Erling Smørgrav static Session * 1895a04a10f8SKris Kennaway session_by_pid(pid_t pid) 1896a04a10f8SKris Kennaway { 1897a04a10f8SKris Kennaway int i; 189880628bacSDag-Erling Smørgrav debug("session_by_pid: pid %ld", (long)pid); 1899d4af9e69SDag-Erling Smørgrav for (i = 0; i < sessions_nalloc; i++) { 1900a04a10f8SKris Kennaway Session *s = &sessions[i]; 1901a04a10f8SKris Kennaway if (s->used && s->pid == pid) 1902a04a10f8SKris Kennaway return s; 1903a04a10f8SKris Kennaway } 190480628bacSDag-Erling Smørgrav error("session_by_pid: unknown pid %ld", (long)pid); 1905a04a10f8SKris Kennaway session_dump(); 1906a04a10f8SKris Kennaway return NULL; 1907a04a10f8SKris Kennaway } 1908a04a10f8SKris Kennaway 1909af12a3e7SDag-Erling Smørgrav static int 19104f52dfbbSDag-Erling Smørgrav session_window_change_req(struct ssh *ssh, Session *s) 1911a04a10f8SKris Kennaway { 191219261079SEd Maste int r; 191319261079SEd Maste 191419261079SEd Maste if ((r = sshpkt_get_u32(ssh, &s->col)) != 0 || 191519261079SEd Maste (r = sshpkt_get_u32(ssh, &s->row)) != 0 || 191619261079SEd Maste (r = sshpkt_get_u32(ssh, &s->xpixel)) != 0 || 191719261079SEd Maste (r = sshpkt_get_u32(ssh, &s->ypixel)) != 0 || 191819261079SEd Maste (r = sshpkt_get_end(ssh)) != 0) 191919261079SEd Maste sshpkt_fatal(ssh, r, "%s: parse packet", __func__); 1920a04a10f8SKris Kennaway pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); 1921a04a10f8SKris Kennaway return 1; 1922a04a10f8SKris Kennaway } 1923a04a10f8SKris Kennaway 1924af12a3e7SDag-Erling Smørgrav static int 19254f52dfbbSDag-Erling Smørgrav session_pty_req(struct ssh *ssh, Session *s) 1926a04a10f8SKris Kennaway { 192719261079SEd Maste int r; 1928a04a10f8SKris Kennaway 192947dd1d1bSDag-Erling Smørgrav if (!auth_opts->permit_pty_flag || !options.permit_tty) { 193047dd1d1bSDag-Erling Smørgrav debug("Allocating a pty not permitted for this connection."); 1931c2d3a559SKris Kennaway return 0; 1932af12a3e7SDag-Erling Smørgrav } 1933af12a3e7SDag-Erling Smørgrav if (s->ttyfd != -1) { 193419261079SEd Maste ssh_packet_disconnect(ssh, "Protocol error: you already have a pty."); 1935a04a10f8SKris Kennaway return 0; 1936af12a3e7SDag-Erling Smørgrav } 1937af12a3e7SDag-Erling Smørgrav 193819261079SEd Maste if ((r = sshpkt_get_cstring(ssh, &s->term, NULL)) != 0 || 193919261079SEd Maste (r = sshpkt_get_u32(ssh, &s->col)) != 0 || 194019261079SEd Maste (r = sshpkt_get_u32(ssh, &s->row)) != 0 || 194119261079SEd Maste (r = sshpkt_get_u32(ssh, &s->xpixel)) != 0 || 194219261079SEd Maste (r = sshpkt_get_u32(ssh, &s->ypixel)) != 0) 194319261079SEd Maste sshpkt_fatal(ssh, r, "%s: parse packet", __func__); 1944a04a10f8SKris Kennaway 1945a04a10f8SKris Kennaway if (strcmp(s->term, "") == 0) { 1946e4a9863fSDag-Erling Smørgrav free(s->term); 1947a04a10f8SKris Kennaway s->term = NULL; 1948a04a10f8SKris Kennaway } 1949af12a3e7SDag-Erling Smørgrav 1950a04a10f8SKris Kennaway /* Allocate a pty and open it. */ 1951af12a3e7SDag-Erling Smørgrav debug("Allocating pty."); 1952d4af9e69SDag-Erling Smørgrav if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, 1953d4af9e69SDag-Erling Smørgrav sizeof(s->tty)))) { 1954e4a9863fSDag-Erling Smørgrav free(s->term); 1955a04a10f8SKris Kennaway s->term = NULL; 1956a04a10f8SKris Kennaway s->ptyfd = -1; 1957a04a10f8SKris Kennaway s->ttyfd = -1; 1958a04a10f8SKris Kennaway error("session_pty_req: session %d alloc failed", s->self); 1959a04a10f8SKris Kennaway return 0; 1960a04a10f8SKris Kennaway } 1961a04a10f8SKris Kennaway debug("session_pty_req: session %d alloc %s", s->self, s->tty); 1962af12a3e7SDag-Erling Smørgrav 1963190cef3dSDag-Erling Smørgrav ssh_tty_parse_modes(ssh, s->ttyfd); 1964af12a3e7SDag-Erling Smørgrav 196519261079SEd Maste if ((r = sshpkt_get_end(ssh)) != 0) 196619261079SEd Maste sshpkt_fatal(ssh, r, "%s: parse packet", __func__); 196719261079SEd Maste 196880628bacSDag-Erling Smørgrav if (!use_privsep) 1969a04a10f8SKris Kennaway pty_setowner(s->pw, s->tty); 1970af12a3e7SDag-Erling Smørgrav 1971af12a3e7SDag-Erling Smørgrav /* Set window size from the packet. */ 1972a04a10f8SKris Kennaway pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); 1973a04a10f8SKris Kennaway 1974a04a10f8SKris Kennaway session_proctitle(s); 1975a04a10f8SKris Kennaway return 1; 1976a04a10f8SKris Kennaway } 1977a04a10f8SKris Kennaway 1978af12a3e7SDag-Erling Smørgrav static int 19794f52dfbbSDag-Erling Smørgrav session_subsystem_req(struct ssh *ssh, Session *s) 1980a04a10f8SKris Kennaway { 1981af12a3e7SDag-Erling Smørgrav struct stat st; 198219261079SEd Maste int r, success = 0; 1983f7167e0eSDag-Erling Smørgrav char *prog, *cmd; 1984d4ecd108SDag-Erling Smørgrav u_int i; 1985a04a10f8SKris Kennaway 198619261079SEd Maste if ((r = sshpkt_get_cstring(ssh, &s->subsys, NULL)) != 0 || 198719261079SEd Maste (r = sshpkt_get_end(ssh)) != 0) 198819261079SEd Maste sshpkt_fatal(ssh, r, "%s: parse packet", __func__); 1989f7167e0eSDag-Erling Smørgrav debug2("subsystem request for %.100s by user %s", s->subsys, 1990e2f6069cSDag-Erling Smørgrav s->pw->pw_name); 1991a04a10f8SKris Kennaway 1992c2d3a559SKris Kennaway for (i = 0; i < options.num_subsystems; i++) { 1993f7167e0eSDag-Erling Smørgrav if (strcmp(s->subsys, options.subsystem_name[i]) == 0) { 1994333ee039SDag-Erling Smørgrav prog = options.subsystem_command[i]; 1995333ee039SDag-Erling Smørgrav cmd = options.subsystem_args[i]; 1996b15c8340SDag-Erling Smørgrav if (strcmp(INTERNAL_SFTP_NAME, prog) == 0) { 1997d4af9e69SDag-Erling Smørgrav s->is_subsystem = SUBSYSTEM_INT_SFTP; 1998b15c8340SDag-Erling Smørgrav debug("subsystem: %s", prog); 1999d4af9e69SDag-Erling Smørgrav } else { 200019261079SEd Maste if (stat(prog, &st) == -1) 2001b15c8340SDag-Erling Smørgrav debug("subsystem: cannot stat %s: %s", 2002b15c8340SDag-Erling Smørgrav prog, strerror(errno)); 2003d4af9e69SDag-Erling Smørgrav s->is_subsystem = SUBSYSTEM_EXT; 2004af12a3e7SDag-Erling Smørgrav debug("subsystem: exec() %s", cmd); 2005b15c8340SDag-Erling Smørgrav } 20064f52dfbbSDag-Erling Smørgrav success = do_exec(ssh, s, cmd) == 0; 2007af12a3e7SDag-Erling Smørgrav break; 2008c2d3a559SKris Kennaway } 2009c2d3a559SKris Kennaway } 2010c2d3a559SKris Kennaway 2011c2d3a559SKris Kennaway if (!success) 2012f7167e0eSDag-Erling Smørgrav logit("subsystem request for %.100s by user %s failed, " 2013f7167e0eSDag-Erling Smørgrav "subsystem not found", s->subsys, s->pw->pw_name); 2014c2d3a559SKris Kennaway 2015a04a10f8SKris Kennaway return success; 2016a04a10f8SKris Kennaway } 2017a04a10f8SKris Kennaway 2018af12a3e7SDag-Erling Smørgrav static int 20194f52dfbbSDag-Erling Smørgrav session_x11_req(struct ssh *ssh, Session *s) 2020a04a10f8SKris Kennaway { 202119261079SEd Maste int r, success; 202219261079SEd Maste u_char single_connection = 0; 2023a04a10f8SKris Kennaway 2024d4ecd108SDag-Erling Smørgrav if (s->auth_proto != NULL || s->auth_data != NULL) { 2025d4ecd108SDag-Erling Smørgrav error("session_x11_req: session %d: " 2026b74df5b2SDag-Erling Smørgrav "x11 forwarding already active", s->self); 2027d4ecd108SDag-Erling Smørgrav return 0; 2028d4ecd108SDag-Erling Smørgrav } 202919261079SEd Maste if ((r = sshpkt_get_u8(ssh, &single_connection)) != 0 || 203019261079SEd Maste (r = sshpkt_get_cstring(ssh, &s->auth_proto, NULL)) != 0 || 203119261079SEd Maste (r = sshpkt_get_cstring(ssh, &s->auth_data, NULL)) != 0 || 203219261079SEd Maste (r = sshpkt_get_u32(ssh, &s->screen)) != 0 || 203319261079SEd Maste (r = sshpkt_get_end(ssh)) != 0) 203419261079SEd Maste sshpkt_fatal(ssh, r, "%s: parse packet", __func__); 203519261079SEd Maste 203619261079SEd Maste s->single_connection = single_connection; 2037a04a10f8SKris Kennaway 2038acc1a9efSDag-Erling Smørgrav if (xauth_valid_string(s->auth_proto) && 2039acc1a9efSDag-Erling Smørgrav xauth_valid_string(s->auth_data)) 20404f52dfbbSDag-Erling Smørgrav success = session_setup_x11fwd(ssh, s); 2041acc1a9efSDag-Erling Smørgrav else { 2042acc1a9efSDag-Erling Smørgrav success = 0; 2043acc1a9efSDag-Erling Smørgrav error("Invalid X11 forwarding data"); 2044acc1a9efSDag-Erling Smørgrav } 2045af12a3e7SDag-Erling Smørgrav if (!success) { 2046e4a9863fSDag-Erling Smørgrav free(s->auth_proto); 2047e4a9863fSDag-Erling Smørgrav free(s->auth_data); 2048af12a3e7SDag-Erling Smørgrav s->auth_proto = NULL; 2049af12a3e7SDag-Erling Smørgrav s->auth_data = NULL; 2050a04a10f8SKris Kennaway } 2051af12a3e7SDag-Erling Smørgrav return success; 2052a04a10f8SKris Kennaway } 2053a04a10f8SKris Kennaway 2054af12a3e7SDag-Erling Smørgrav static int 20554f52dfbbSDag-Erling Smørgrav session_shell_req(struct ssh *ssh, Session *s) 2056c2d3a559SKris Kennaway { 205719261079SEd Maste int r; 205819261079SEd Maste 205919261079SEd Maste if ((r = sshpkt_get_end(ssh)) != 0) 206019261079SEd Maste sshpkt_fatal(ssh, r, "%s: parse packet", __func__); 20614f52dfbbSDag-Erling Smørgrav return do_exec(ssh, s, NULL) == 0; 2062c2d3a559SKris Kennaway } 2063c2d3a559SKris Kennaway 2064af12a3e7SDag-Erling Smørgrav static int 20654f52dfbbSDag-Erling Smørgrav session_exec_req(struct ssh *ssh, Session *s) 2066c2d3a559SKris Kennaway { 206719261079SEd Maste u_int success; 206819261079SEd Maste int r; 206919261079SEd Maste char *command = NULL; 2070d4af9e69SDag-Erling Smørgrav 207119261079SEd Maste if ((r = sshpkt_get_cstring(ssh, &command, NULL)) != 0 || 207219261079SEd Maste (r = sshpkt_get_end(ssh)) != 0) 207319261079SEd Maste sshpkt_fatal(ssh, r, "%s: parse packet", __func__); 207419261079SEd Maste 20754f52dfbbSDag-Erling Smørgrav success = do_exec(ssh, s, command) == 0; 2076e4a9863fSDag-Erling Smørgrav free(command); 2077d4af9e69SDag-Erling Smørgrav return success; 2078c2d3a559SKris Kennaway } 2079c2d3a559SKris Kennaway 2080af12a3e7SDag-Erling Smørgrav static int 20814f52dfbbSDag-Erling Smørgrav session_break_req(struct ssh *ssh, Session *s) 2082cf2b5f3bSDag-Erling Smørgrav { 208319261079SEd Maste int r; 2084cf2b5f3bSDag-Erling Smørgrav 208519261079SEd Maste if ((r = sshpkt_get_u32(ssh, NULL)) != 0 || /* ignore */ 208619261079SEd Maste (r = sshpkt_get_end(ssh)) != 0) 208719261079SEd Maste sshpkt_fatal(ssh, r, "%s: parse packet", __func__); 2088cf2b5f3bSDag-Erling Smørgrav 208919261079SEd Maste if (s->ptymaster == -1 || tcsendbreak(s->ptymaster, 0) == -1) 2090cf2b5f3bSDag-Erling Smørgrav return 0; 2091cf2b5f3bSDag-Erling Smørgrav return 1; 2092cf2b5f3bSDag-Erling Smørgrav } 2093cf2b5f3bSDag-Erling Smørgrav 2094cf2b5f3bSDag-Erling Smørgrav static int 20954f52dfbbSDag-Erling Smørgrav session_env_req(struct ssh *ssh, Session *s) 209621e764dfSDag-Erling Smørgrav { 209721e764dfSDag-Erling Smørgrav char *name, *val; 209819261079SEd Maste u_int i; 209919261079SEd Maste int r; 210021e764dfSDag-Erling Smørgrav 210119261079SEd Maste if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0 || 210219261079SEd Maste (r = sshpkt_get_cstring(ssh, &val, NULL)) != 0 || 210319261079SEd Maste (r = sshpkt_get_end(ssh)) != 0) 210419261079SEd Maste sshpkt_fatal(ssh, r, "%s: parse packet", __func__); 210521e764dfSDag-Erling Smørgrav 210621e764dfSDag-Erling Smørgrav /* Don't set too many environment variables */ 210721e764dfSDag-Erling Smørgrav if (s->num_env > 128) { 210821e764dfSDag-Erling Smørgrav debug2("Ignoring env request %s: too many env vars", name); 210921e764dfSDag-Erling Smørgrav goto fail; 211021e764dfSDag-Erling Smørgrav } 211121e764dfSDag-Erling Smørgrav 211221e764dfSDag-Erling Smørgrav for (i = 0; i < options.num_accept_env; i++) { 211321e764dfSDag-Erling Smørgrav if (match_pattern(name, options.accept_env[i])) { 211421e764dfSDag-Erling Smørgrav debug2("Setting env %d: %s=%s", s->num_env, name, val); 21154f52dfbbSDag-Erling Smørgrav s->env = xrecallocarray(s->env, s->num_env, 21164f52dfbbSDag-Erling Smørgrav s->num_env + 1, sizeof(*s->env)); 211721e764dfSDag-Erling Smørgrav s->env[s->num_env].name = name; 211821e764dfSDag-Erling Smørgrav s->env[s->num_env].val = val; 211921e764dfSDag-Erling Smørgrav s->num_env++; 212021e764dfSDag-Erling Smørgrav return (1); 212121e764dfSDag-Erling Smørgrav } 212221e764dfSDag-Erling Smørgrav } 212321e764dfSDag-Erling Smørgrav debug2("Ignoring env request %s: disallowed name", name); 212421e764dfSDag-Erling Smørgrav 212521e764dfSDag-Erling Smørgrav fail: 2126e4a9863fSDag-Erling Smørgrav free(name); 2127e4a9863fSDag-Erling Smørgrav free(val); 212821e764dfSDag-Erling Smørgrav return (0); 212921e764dfSDag-Erling Smørgrav } 213021e764dfSDag-Erling Smørgrav 21312f513db7SEd Maste /* 21322f513db7SEd Maste * Conversion of signals from ssh channel request names. 21332f513db7SEd Maste * Subset of signals from RFC 4254 section 6.10C, with SIGINFO as 21342f513db7SEd Maste * local extension. 21352f513db7SEd Maste */ 21362f513db7SEd Maste static int 21372f513db7SEd Maste name2sig(char *name) 21382f513db7SEd Maste { 21392f513db7SEd Maste #define SSH_SIG(x) if (strcmp(name, #x) == 0) return SIG ## x 21402f513db7SEd Maste SSH_SIG(HUP); 21412f513db7SEd Maste SSH_SIG(INT); 21422f513db7SEd Maste SSH_SIG(KILL); 21432f513db7SEd Maste SSH_SIG(QUIT); 21442f513db7SEd Maste SSH_SIG(TERM); 21452f513db7SEd Maste SSH_SIG(USR1); 21462f513db7SEd Maste SSH_SIG(USR2); 21472f513db7SEd Maste #undef SSH_SIG 21482f513db7SEd Maste #ifdef SIGINFO 21492f513db7SEd Maste if (strcmp(name, "INFO@openssh.com") == 0) 21502f513db7SEd Maste return SIGINFO; 21512f513db7SEd Maste #endif 21522f513db7SEd Maste return -1; 21532f513db7SEd Maste } 21542f513db7SEd Maste 21552f513db7SEd Maste static int 21562f513db7SEd Maste session_signal_req(struct ssh *ssh, Session *s) 21572f513db7SEd Maste { 21582f513db7SEd Maste char *signame = NULL; 21592f513db7SEd Maste int r, sig, success = 0; 21602f513db7SEd Maste 21612f513db7SEd Maste if ((r = sshpkt_get_cstring(ssh, &signame, NULL)) != 0 || 21622f513db7SEd Maste (r = sshpkt_get_end(ssh)) != 0) { 216319261079SEd Maste error_fr(r, "parse"); 21642f513db7SEd Maste goto out; 21652f513db7SEd Maste } 21662f513db7SEd Maste if ((sig = name2sig(signame)) == -1) { 216719261079SEd Maste error_f("unsupported signal \"%s\"", signame); 21682f513db7SEd Maste goto out; 21692f513db7SEd Maste } 21702f513db7SEd Maste if (s->pid <= 0) { 217119261079SEd Maste error_f("no pid for session %d", s->self); 21722f513db7SEd Maste goto out; 21732f513db7SEd Maste } 21742f513db7SEd Maste if (s->forced || s->is_subsystem) { 217519261079SEd Maste error_f("refusing to send signal %s to %s session", 21762f513db7SEd Maste signame, s->forced ? "forced-command" : "subsystem"); 21772f513db7SEd Maste goto out; 21782f513db7SEd Maste } 21792f513db7SEd Maste if (!use_privsep || mm_is_monitor()) { 218019261079SEd Maste error_f("session signalling requires privilege separation"); 21812f513db7SEd Maste goto out; 21822f513db7SEd Maste } 21832f513db7SEd Maste 218419261079SEd Maste debug_f("signal %s, killpg(%ld, %d)", signame, (long)s->pid, sig); 21852f513db7SEd Maste temporarily_use_uid(s->pw); 21862f513db7SEd Maste r = killpg(s->pid, sig); 21872f513db7SEd Maste restore_uid(); 21882f513db7SEd Maste if (r != 0) { 218919261079SEd Maste error_f("killpg(%ld, %d): %s", (long)s->pid, 21902f513db7SEd Maste sig, strerror(errno)); 21912f513db7SEd Maste goto out; 21922f513db7SEd Maste } 21932f513db7SEd Maste 21942f513db7SEd Maste /* success */ 21952f513db7SEd Maste success = 1; 21962f513db7SEd Maste out: 21972f513db7SEd Maste free(signame); 21982f513db7SEd Maste return success; 21992f513db7SEd Maste } 22002f513db7SEd Maste 220121e764dfSDag-Erling Smørgrav static int 22024f52dfbbSDag-Erling Smørgrav session_auth_agent_req(struct ssh *ssh, Session *s) 2203ca3176e7SBrian Feldman { 2204ca3176e7SBrian Feldman static int called = 0; 220519261079SEd Maste int r; 220647dd1d1bSDag-Erling Smørgrav 220719261079SEd Maste if ((r = sshpkt_get_end(ssh)) != 0) 220819261079SEd Maste sshpkt_fatal(ssh, r, "%s: parse packet", __func__); 220947dd1d1bSDag-Erling Smørgrav if (!auth_opts->permit_agent_forwarding_flag || 221047dd1d1bSDag-Erling Smørgrav !options.allow_agent_forwarding) { 221119261079SEd Maste debug_f("agent forwarding disabled"); 2212ca3176e7SBrian Feldman return 0; 2213ca3176e7SBrian Feldman } 2214ca3176e7SBrian Feldman if (called) { 2215ca3176e7SBrian Feldman return 0; 2216ca3176e7SBrian Feldman } else { 2217ca3176e7SBrian Feldman called = 1; 22184f52dfbbSDag-Erling Smørgrav return auth_input_request_forwarding(ssh, s->pw); 2219ca3176e7SBrian Feldman } 2220ca3176e7SBrian Feldman } 2221ca3176e7SBrian Feldman 2222af12a3e7SDag-Erling Smørgrav int 22234f52dfbbSDag-Erling Smørgrav session_input_channel_req(struct ssh *ssh, Channel *c, const char *rtype) 2224a04a10f8SKris Kennaway { 2225a04a10f8SKris Kennaway int success = 0; 2226a04a10f8SKris Kennaway Session *s; 2227a04a10f8SKris Kennaway 2228af12a3e7SDag-Erling Smørgrav if ((s = session_by_channel(c->self)) == NULL) { 222919261079SEd Maste logit_f("no session %d req %.100s", c->self, rtype); 2230af12a3e7SDag-Erling Smørgrav return 0; 2231af12a3e7SDag-Erling Smørgrav } 223219261079SEd Maste debug_f("session %d req %s", s->self, rtype); 2233a04a10f8SKris Kennaway 2234a04a10f8SKris Kennaway /* 2235ca3176e7SBrian Feldman * a session is in LARVAL state until a shell, a command 2236ca3176e7SBrian Feldman * or a subsystem is executed 2237a04a10f8SKris Kennaway */ 2238a04a10f8SKris Kennaway if (c->type == SSH_CHANNEL_LARVAL) { 2239a04a10f8SKris Kennaway if (strcmp(rtype, "shell") == 0) { 22404f52dfbbSDag-Erling Smørgrav success = session_shell_req(ssh, s); 2241a04a10f8SKris Kennaway } else if (strcmp(rtype, "exec") == 0) { 22424f52dfbbSDag-Erling Smørgrav success = session_exec_req(ssh, s); 2243a04a10f8SKris Kennaway } else if (strcmp(rtype, "pty-req") == 0) { 22444f52dfbbSDag-Erling Smørgrav success = session_pty_req(ssh, s); 2245a04a10f8SKris Kennaway } else if (strcmp(rtype, "x11-req") == 0) { 22464f52dfbbSDag-Erling Smørgrav success = session_x11_req(ssh, s); 2247ca3176e7SBrian Feldman } else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) { 22484f52dfbbSDag-Erling Smørgrav success = session_auth_agent_req(ssh, s); 2249a04a10f8SKris Kennaway } else if (strcmp(rtype, "subsystem") == 0) { 22504f52dfbbSDag-Erling Smørgrav success = session_subsystem_req(ssh, s); 225121e764dfSDag-Erling Smørgrav } else if (strcmp(rtype, "env") == 0) { 22524f52dfbbSDag-Erling Smørgrav success = session_env_req(ssh, s); 2253a04a10f8SKris Kennaway } 2254a04a10f8SKris Kennaway } 2255a04a10f8SKris Kennaway if (strcmp(rtype, "window-change") == 0) { 22564f52dfbbSDag-Erling Smørgrav success = session_window_change_req(ssh, s); 225721e764dfSDag-Erling Smørgrav } else if (strcmp(rtype, "break") == 0) { 22584f52dfbbSDag-Erling Smørgrav success = session_break_req(ssh, s); 22592f513db7SEd Maste } else if (strcmp(rtype, "signal") == 0) { 22602f513db7SEd Maste success = session_signal_req(ssh, s); 2261a04a10f8SKris Kennaway } 226221e764dfSDag-Erling Smørgrav 2263af12a3e7SDag-Erling Smørgrav return success; 2264a04a10f8SKris Kennaway } 2265a04a10f8SKris Kennaway 2266a04a10f8SKris Kennaway void 22674f52dfbbSDag-Erling Smørgrav session_set_fds(struct ssh *ssh, Session *s, 22684f52dfbbSDag-Erling Smørgrav int fdin, int fdout, int fderr, int ignore_fderr, int is_tty) 2269a04a10f8SKris Kennaway { 2270a04a10f8SKris Kennaway /* 2271a04a10f8SKris Kennaway * now that have a child and a pipe to the child, 2272a04a10f8SKris Kennaway * we can activate our channel and register the fd's 2273a04a10f8SKris Kennaway */ 2274a04a10f8SKris Kennaway if (s->chanid == -1) 2275a04a10f8SKris Kennaway fatal("no channel for session %d", s->self); 22764f52dfbbSDag-Erling Smørgrav channel_set_fds(ssh, s->chanid, 227760c59fadSDag-Erling Smørgrav fdout, fdin, fderr, 2278e2f6069cSDag-Erling Smørgrav ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, 2279d4af9e69SDag-Erling Smørgrav 1, is_tty, CHAN_SES_WINDOW_DEFAULT); 2280a04a10f8SKris Kennaway } 2281a04a10f8SKris Kennaway 2282af12a3e7SDag-Erling Smørgrav /* 2283af12a3e7SDag-Erling Smørgrav * Function to perform pty cleanup. Also called if we get aborted abnormally 2284af12a3e7SDag-Erling Smørgrav * (e.g., due to a dropped connection). 2285af12a3e7SDag-Erling Smørgrav */ 228680628bacSDag-Erling Smørgrav void 22871ec0d754SDag-Erling Smørgrav session_pty_cleanup2(Session *s) 2288a04a10f8SKris Kennaway { 2289af12a3e7SDag-Erling Smørgrav if (s == NULL) { 229019261079SEd Maste error_f("no session"); 2291af12a3e7SDag-Erling Smørgrav return; 2292af12a3e7SDag-Erling Smørgrav } 2293af12a3e7SDag-Erling Smørgrav if (s->ttyfd == -1) 2294a04a10f8SKris Kennaway return; 2295a04a10f8SKris Kennaway 229619261079SEd Maste debug_f("session %d release %s", s->self, s->tty); 2297a04a10f8SKris Kennaway 2298a04a10f8SKris Kennaway /* Record that the user has logged out. */ 2299af12a3e7SDag-Erling Smørgrav if (s->pid != 0) 2300989dd127SDag-Erling Smørgrav record_logout(s->pid, s->tty, s->pw->pw_name); 2301a04a10f8SKris Kennaway 2302a04a10f8SKris Kennaway /* Release the pseudo-tty. */ 230380628bacSDag-Erling Smørgrav if (getuid() == 0) 2304a04a10f8SKris Kennaway pty_release(s->tty); 2305a04a10f8SKris Kennaway 2306a04a10f8SKris Kennaway /* 2307a04a10f8SKris Kennaway * Close the server side of the socket pairs. We must do this after 2308a04a10f8SKris Kennaway * the pty cleanup, so that another process doesn't get this pty 2309a04a10f8SKris Kennaway * while we're still cleaning up. 2310a04a10f8SKris Kennaway */ 231119261079SEd Maste if (s->ptymaster != -1 && close(s->ptymaster) == -1) 2312d4af9e69SDag-Erling Smørgrav error("close(s->ptymaster/%d): %s", 2313d4af9e69SDag-Erling Smørgrav s->ptymaster, strerror(errno)); 2314af12a3e7SDag-Erling Smørgrav 2315af12a3e7SDag-Erling Smørgrav /* unlink pty from session */ 2316af12a3e7SDag-Erling Smørgrav s->ttyfd = -1; 2317a04a10f8SKris Kennaway } 2318a04a10f8SKris Kennaway 231980628bacSDag-Erling Smørgrav void 23201ec0d754SDag-Erling Smørgrav session_pty_cleanup(Session *s) 232180628bacSDag-Erling Smørgrav { 23221ec0d754SDag-Erling Smørgrav PRIVSEP(session_pty_cleanup2(s)); 232380628bacSDag-Erling Smørgrav } 232480628bacSDag-Erling Smørgrav 2325f388f5efSDag-Erling Smørgrav static char * 2326f388f5efSDag-Erling Smørgrav sig2name(int sig) 2327f388f5efSDag-Erling Smørgrav { 2328f388f5efSDag-Erling Smørgrav #define SSH_SIG(x) if (sig == SIG ## x) return #x 2329f388f5efSDag-Erling Smørgrav SSH_SIG(ABRT); 2330f388f5efSDag-Erling Smørgrav SSH_SIG(ALRM); 2331f388f5efSDag-Erling Smørgrav SSH_SIG(FPE); 2332f388f5efSDag-Erling Smørgrav SSH_SIG(HUP); 2333f388f5efSDag-Erling Smørgrav SSH_SIG(ILL); 2334f388f5efSDag-Erling Smørgrav SSH_SIG(INT); 2335f388f5efSDag-Erling Smørgrav SSH_SIG(KILL); 2336f388f5efSDag-Erling Smørgrav SSH_SIG(PIPE); 2337f388f5efSDag-Erling Smørgrav SSH_SIG(QUIT); 2338f388f5efSDag-Erling Smørgrav SSH_SIG(SEGV); 2339f388f5efSDag-Erling Smørgrav SSH_SIG(TERM); 2340f388f5efSDag-Erling Smørgrav SSH_SIG(USR1); 2341f388f5efSDag-Erling Smørgrav SSH_SIG(USR2); 2342f388f5efSDag-Erling Smørgrav #undef SSH_SIG 2343f388f5efSDag-Erling Smørgrav return "SIG@openssh.com"; 2344f388f5efSDag-Erling Smørgrav } 2345f388f5efSDag-Erling Smørgrav 2346af12a3e7SDag-Erling Smørgrav static void 23474f52dfbbSDag-Erling Smørgrav session_close_x11(struct ssh *ssh, int id) 2348d4ecd108SDag-Erling Smørgrav { 2349d4ecd108SDag-Erling Smørgrav Channel *c; 2350d4ecd108SDag-Erling Smørgrav 23514f52dfbbSDag-Erling Smørgrav if ((c = channel_by_id(ssh, id)) == NULL) { 235219261079SEd Maste debug_f("x11 channel %d missing", id); 2353d4ecd108SDag-Erling Smørgrav } else { 2354d4ecd108SDag-Erling Smørgrav /* Detach X11 listener */ 235519261079SEd Maste debug_f("detach x11 channel %d", id); 23564f52dfbbSDag-Erling Smørgrav channel_cancel_cleanup(ssh, id); 2357d4ecd108SDag-Erling Smørgrav if (c->ostate != CHAN_OUTPUT_CLOSED) 23584f52dfbbSDag-Erling Smørgrav chan_mark_dead(ssh, c); 2359d4ecd108SDag-Erling Smørgrav } 2360d4ecd108SDag-Erling Smørgrav } 2361d4ecd108SDag-Erling Smørgrav 2362d4ecd108SDag-Erling Smørgrav static void 23634f52dfbbSDag-Erling Smørgrav session_close_single_x11(struct ssh *ssh, int id, void *arg) 2364d4ecd108SDag-Erling Smørgrav { 2365d4ecd108SDag-Erling Smørgrav Session *s; 2366d4ecd108SDag-Erling Smørgrav u_int i; 2367d4ecd108SDag-Erling Smørgrav 236819261079SEd Maste debug3_f("channel %d", id); 23694f52dfbbSDag-Erling Smørgrav channel_cancel_cleanup(ssh, id); 2370d4ecd108SDag-Erling Smørgrav if ((s = session_by_x11_channel(id)) == NULL) 237119261079SEd Maste fatal_f("no x11 channel %d", id); 2372d4ecd108SDag-Erling Smørgrav for (i = 0; s->x11_chanids[i] != -1; i++) { 237319261079SEd Maste debug_f("session %d: closing channel %d", 237419261079SEd Maste s->self, s->x11_chanids[i]); 2375d4ecd108SDag-Erling Smørgrav /* 2376d4ecd108SDag-Erling Smørgrav * The channel "id" is already closing, but make sure we 2377d4ecd108SDag-Erling Smørgrav * close all of its siblings. 2378d4ecd108SDag-Erling Smørgrav */ 2379d4ecd108SDag-Erling Smørgrav if (s->x11_chanids[i] != id) 23804f52dfbbSDag-Erling Smørgrav session_close_x11(ssh, s->x11_chanids[i]); 2381d4ecd108SDag-Erling Smørgrav } 2382e4a9863fSDag-Erling Smørgrav free(s->x11_chanids); 2383d4ecd108SDag-Erling Smørgrav s->x11_chanids = NULL; 2384e4a9863fSDag-Erling Smørgrav free(s->display); 2385d4ecd108SDag-Erling Smørgrav s->display = NULL; 2386e4a9863fSDag-Erling Smørgrav free(s->auth_proto); 2387d4ecd108SDag-Erling Smørgrav s->auth_proto = NULL; 2388e4a9863fSDag-Erling Smørgrav free(s->auth_data); 2389d4ecd108SDag-Erling Smørgrav s->auth_data = NULL; 2390e4a9863fSDag-Erling Smørgrav free(s->auth_display); 2391d4ecd108SDag-Erling Smørgrav s->auth_display = NULL; 2392d4ecd108SDag-Erling Smørgrav } 2393d4ecd108SDag-Erling Smørgrav 2394d4ecd108SDag-Erling Smørgrav static void 23954f52dfbbSDag-Erling Smørgrav session_exit_message(struct ssh *ssh, Session *s, int status) 2396a04a10f8SKris Kennaway { 2397a04a10f8SKris Kennaway Channel *c; 239819261079SEd Maste int r; 2399af12a3e7SDag-Erling Smørgrav 24004f52dfbbSDag-Erling Smørgrav if ((c = channel_lookup(ssh, s->chanid)) == NULL) 240119261079SEd Maste fatal_f("session %d: no channel %d", s->self, s->chanid); 240219261079SEd Maste debug_f("session %d channel %d pid %ld", 240319261079SEd Maste s->self, s->chanid, (long)s->pid); 2404a04a10f8SKris Kennaway 2405a04a10f8SKris Kennaway if (WIFEXITED(status)) { 24064f52dfbbSDag-Erling Smørgrav channel_request_start(ssh, s->chanid, "exit-status", 0); 240719261079SEd Maste if ((r = sshpkt_put_u32(ssh, WEXITSTATUS(status))) != 0 || 240819261079SEd Maste (r = sshpkt_send(ssh)) != 0) 240919261079SEd Maste sshpkt_fatal(ssh, r, "%s: exit reply", __func__); 2410a04a10f8SKris Kennaway } else if (WIFSIGNALED(status)) { 24114f52dfbbSDag-Erling Smørgrav channel_request_start(ssh, s->chanid, "exit-signal", 0); 241219261079SEd Maste #ifndef WCOREDUMP 241319261079SEd Maste # define WCOREDUMP(x) (0) 241419261079SEd Maste #endif 241519261079SEd Maste if ((r = sshpkt_put_cstring(ssh, sig2name(WTERMSIG(status)))) != 0 || 241619261079SEd Maste (r = sshpkt_put_u8(ssh, WCOREDUMP(status)? 1 : 0)) != 0 || 241719261079SEd Maste (r = sshpkt_put_cstring(ssh, "")) != 0 || 241819261079SEd Maste (r = sshpkt_put_cstring(ssh, "")) != 0 || 241919261079SEd Maste (r = sshpkt_send(ssh)) != 0) 242019261079SEd Maste sshpkt_fatal(ssh, r, "%s: exit reply", __func__); 2421a04a10f8SKris Kennaway } else { 2422a04a10f8SKris Kennaway /* Some weird exit cause. Just exit. */ 242319261079SEd Maste ssh_packet_disconnect(ssh, "wait returned status %04x.", status); 2424a04a10f8SKris Kennaway } 2425a04a10f8SKris Kennaway 2426a04a10f8SKris Kennaway /* disconnect channel */ 242719261079SEd Maste debug_f("release channel %d", s->chanid); 2428b74df5b2SDag-Erling Smørgrav 2429b74df5b2SDag-Erling Smørgrav /* 2430b74df5b2SDag-Erling Smørgrav * Adjust cleanup callback attachment to send close messages when 2431b74df5b2SDag-Erling Smørgrav * the channel gets EOF. The session will be then be closed 243219261079SEd Maste * by session_close_by_channel when the child sessions close their fds. 2433b74df5b2SDag-Erling Smørgrav */ 24344f52dfbbSDag-Erling Smørgrav channel_register_cleanup(ssh, c->self, session_close_by_channel, 1); 2435b74df5b2SDag-Erling Smørgrav 2436a04a10f8SKris Kennaway /* 2437a04a10f8SKris Kennaway * emulate a write failure with 'chan_write_failed', nobody will be 2438a04a10f8SKris Kennaway * interested in data we write. 2439a04a10f8SKris Kennaway * Note that we must not call 'chan_read_failed', since there could 2440a04a10f8SKris Kennaway * be some more data waiting in the pipe. 2441a04a10f8SKris Kennaway */ 2442a04a10f8SKris Kennaway if (c->ostate != CHAN_OUTPUT_CLOSED) 24434f52dfbbSDag-Erling Smørgrav chan_write_failed(ssh, c); 2444a04a10f8SKris Kennaway } 2445a04a10f8SKris Kennaway 244680628bacSDag-Erling Smørgrav void 24474f52dfbbSDag-Erling Smørgrav session_close(struct ssh *ssh, Session *s) 2448a04a10f8SKris Kennaway { 2449d4ecd108SDag-Erling Smørgrav u_int i; 245021e764dfSDag-Erling Smørgrav 2451acc1a9efSDag-Erling Smørgrav verbose("Close session: user %s from %.200s port %d id %d", 2452acc1a9efSDag-Erling Smørgrav s->pw->pw_name, 2453076ad2f8SDag-Erling Smørgrav ssh_remote_ipaddr(ssh), 2454076ad2f8SDag-Erling Smørgrav ssh_remote_port(ssh), 2455acc1a9efSDag-Erling Smørgrav s->self); 2456acc1a9efSDag-Erling Smørgrav 24571ec0d754SDag-Erling Smørgrav if (s->ttyfd != -1) 2458af12a3e7SDag-Erling Smørgrav session_pty_cleanup(s); 2459e4a9863fSDag-Erling Smørgrav free(s->term); 2460e4a9863fSDag-Erling Smørgrav free(s->display); 2461e4a9863fSDag-Erling Smørgrav free(s->x11_chanids); 2462e4a9863fSDag-Erling Smørgrav free(s->auth_display); 2463e4a9863fSDag-Erling Smørgrav free(s->auth_data); 2464e4a9863fSDag-Erling Smørgrav free(s->auth_proto); 2465f7167e0eSDag-Erling Smørgrav free(s->subsys); 2466333ee039SDag-Erling Smørgrav if (s->env != NULL) { 246721e764dfSDag-Erling Smørgrav for (i = 0; i < s->num_env; i++) { 2468e4a9863fSDag-Erling Smørgrav free(s->env[i].name); 2469e4a9863fSDag-Erling Smørgrav free(s->env[i].val); 247021e764dfSDag-Erling Smørgrav } 2471e4a9863fSDag-Erling Smørgrav free(s->env); 2472333ee039SDag-Erling Smørgrav } 2473a04a10f8SKris Kennaway session_proctitle(s); 2474d4af9e69SDag-Erling Smørgrav session_unused(s->self); 2475a04a10f8SKris Kennaway } 2476a04a10f8SKris Kennaway 2477a04a10f8SKris Kennaway void 24784f52dfbbSDag-Erling Smørgrav session_close_by_pid(struct ssh *ssh, pid_t pid, int status) 2479a04a10f8SKris Kennaway { 2480a04a10f8SKris Kennaway Session *s = session_by_pid(pid); 2481a04a10f8SKris Kennaway if (s == NULL) { 248219261079SEd Maste debug_f("no session for pid %ld", (long)pid); 2483a04a10f8SKris Kennaway return; 2484a04a10f8SKris Kennaway } 2485a04a10f8SKris Kennaway if (s->chanid != -1) 24864f52dfbbSDag-Erling Smørgrav session_exit_message(ssh, s, status); 2487b74df5b2SDag-Erling Smørgrav if (s->ttyfd != -1) 2488b74df5b2SDag-Erling Smørgrav session_pty_cleanup(s); 2489333ee039SDag-Erling Smørgrav s->pid = 0; 2490a04a10f8SKris Kennaway } 2491a04a10f8SKris Kennaway 2492a04a10f8SKris Kennaway /* 2493a04a10f8SKris Kennaway * this is called when a channel dies before 2494a04a10f8SKris Kennaway * the session 'child' itself dies 2495a04a10f8SKris Kennaway */ 2496a04a10f8SKris Kennaway void 24974f52dfbbSDag-Erling Smørgrav session_close_by_channel(struct ssh *ssh, int id, void *arg) 2498a04a10f8SKris Kennaway { 2499a04a10f8SKris Kennaway Session *s = session_by_channel(id); 2500b74df5b2SDag-Erling Smørgrav u_int i; 2501d4ecd108SDag-Erling Smørgrav 2502a04a10f8SKris Kennaway if (s == NULL) { 250319261079SEd Maste debug_f("no session for id %d", id); 2504a04a10f8SKris Kennaway return; 2505a04a10f8SKris Kennaway } 250619261079SEd Maste debug_f("channel %d child %ld", id, (long)s->pid); 2507af12a3e7SDag-Erling Smørgrav if (s->pid != 0) { 250819261079SEd Maste debug_f("channel %d: has child, ttyfd %d", id, s->ttyfd); 2509af12a3e7SDag-Erling Smørgrav /* 2510af12a3e7SDag-Erling Smørgrav * delay detach of session, but release pty, since 2511af12a3e7SDag-Erling Smørgrav * the fd's to the child are already closed 2512af12a3e7SDag-Erling Smørgrav */ 25131ec0d754SDag-Erling Smørgrav if (s->ttyfd != -1) 2514af12a3e7SDag-Erling Smørgrav session_pty_cleanup(s); 2515af12a3e7SDag-Erling Smørgrav return; 2516af12a3e7SDag-Erling Smørgrav } 2517af12a3e7SDag-Erling Smørgrav /* detach by removing callback */ 25184f52dfbbSDag-Erling Smørgrav channel_cancel_cleanup(ssh, s->chanid); 2519b74df5b2SDag-Erling Smørgrav 2520b74df5b2SDag-Erling Smørgrav /* Close any X11 listeners associated with this session */ 2521b74df5b2SDag-Erling Smørgrav if (s->x11_chanids != NULL) { 2522b74df5b2SDag-Erling Smørgrav for (i = 0; s->x11_chanids[i] != -1; i++) { 25234f52dfbbSDag-Erling Smørgrav session_close_x11(ssh, s->x11_chanids[i]); 2524b74df5b2SDag-Erling Smørgrav s->x11_chanids[i] = -1; 2525b74df5b2SDag-Erling Smørgrav } 2526b74df5b2SDag-Erling Smørgrav } 2527b74df5b2SDag-Erling Smørgrav 2528a04a10f8SKris Kennaway s->chanid = -1; 25294f52dfbbSDag-Erling Smørgrav session_close(ssh, s); 2530af12a3e7SDag-Erling Smørgrav } 2531af12a3e7SDag-Erling Smørgrav 2532af12a3e7SDag-Erling Smørgrav void 25334f52dfbbSDag-Erling Smørgrav session_destroy_all(struct ssh *ssh, void (*closefunc)(Session *)) 2534af12a3e7SDag-Erling Smørgrav { 2535af12a3e7SDag-Erling Smørgrav int i; 2536d4af9e69SDag-Erling Smørgrav for (i = 0; i < sessions_nalloc; i++) { 2537af12a3e7SDag-Erling Smørgrav Session *s = &sessions[i]; 253880628bacSDag-Erling Smørgrav if (s->used) { 253980628bacSDag-Erling Smørgrav if (closefunc != NULL) 254080628bacSDag-Erling Smørgrav closefunc(s); 254180628bacSDag-Erling Smørgrav else 25424f52dfbbSDag-Erling Smørgrav session_close(ssh, s); 2543a04a10f8SKris Kennaway } 2544a04a10f8SKris Kennaway } 254580628bacSDag-Erling Smørgrav } 2546a04a10f8SKris Kennaway 2547af12a3e7SDag-Erling Smørgrav static char * 2548a04a10f8SKris Kennaway session_tty_list(void) 2549a04a10f8SKris Kennaway { 2550a04a10f8SKris Kennaway static char buf[1024]; 2551a04a10f8SKris Kennaway int i; 2552e73e9afaSDag-Erling Smørgrav char *cp; 2553e73e9afaSDag-Erling Smørgrav 2554a04a10f8SKris Kennaway buf[0] = '\0'; 2555d4af9e69SDag-Erling Smørgrav for (i = 0; i < sessions_nalloc; i++) { 2556a04a10f8SKris Kennaway Session *s = &sessions[i]; 2557a04a10f8SKris Kennaway if (s->used && s->ttyfd != -1) { 2558e73e9afaSDag-Erling Smørgrav 2559e73e9afaSDag-Erling Smørgrav if (strncmp(s->tty, "/dev/", 5) != 0) { 2560e73e9afaSDag-Erling Smørgrav cp = strrchr(s->tty, '/'); 2561e73e9afaSDag-Erling Smørgrav cp = (cp == NULL) ? s->tty : cp + 1; 2562e73e9afaSDag-Erling Smørgrav } else 2563e73e9afaSDag-Erling Smørgrav cp = s->tty + 5; 2564e73e9afaSDag-Erling Smørgrav 2565a04a10f8SKris Kennaway if (buf[0] != '\0') 2566a04a10f8SKris Kennaway strlcat(buf, ",", sizeof buf); 2567e73e9afaSDag-Erling Smørgrav strlcat(buf, cp, sizeof buf); 2568a04a10f8SKris Kennaway } 2569a04a10f8SKris Kennaway } 2570a04a10f8SKris Kennaway if (buf[0] == '\0') 2571a04a10f8SKris Kennaway strlcpy(buf, "notty", sizeof buf); 2572a04a10f8SKris Kennaway return buf; 2573a04a10f8SKris Kennaway } 2574a04a10f8SKris Kennaway 2575a04a10f8SKris Kennaway void 2576a04a10f8SKris Kennaway session_proctitle(Session *s) 2577a04a10f8SKris Kennaway { 2578a04a10f8SKris Kennaway if (s->pw == NULL) 2579a04a10f8SKris Kennaway error("no user for session %d", s->self); 2580a04a10f8SKris Kennaway else 2581a04a10f8SKris Kennaway setproctitle("%s@%s", s->pw->pw_name, session_tty_list()); 2582a04a10f8SKris Kennaway } 2583a04a10f8SKris Kennaway 2584af12a3e7SDag-Erling Smørgrav int 25854f52dfbbSDag-Erling Smørgrav session_setup_x11fwd(struct ssh *ssh, Session *s) 2586af12a3e7SDag-Erling Smørgrav { 2587af12a3e7SDag-Erling Smørgrav struct stat st; 2588af12a3e7SDag-Erling Smørgrav char display[512], auth_display[512]; 2589a0ee8cc6SDag-Erling Smørgrav char hostname[NI_MAXHOST]; 2590d4ecd108SDag-Erling Smørgrav u_int i; 2591af12a3e7SDag-Erling Smørgrav 259247dd1d1bSDag-Erling Smørgrav if (!auth_opts->permit_x11_forwarding_flag) { 259319261079SEd Maste ssh_packet_send_debug(ssh, "X11 forwarding disabled by key options."); 2594af12a3e7SDag-Erling Smørgrav return 0; 2595af12a3e7SDag-Erling Smørgrav } 2596af12a3e7SDag-Erling Smørgrav if (!options.x11_forwarding) { 2597af12a3e7SDag-Erling Smørgrav debug("X11 forwarding disabled in server configuration file."); 2598af12a3e7SDag-Erling Smørgrav return 0; 2599af12a3e7SDag-Erling Smørgrav } 2600bc5531deSDag-Erling Smørgrav if (options.xauth_location == NULL || 2601af12a3e7SDag-Erling Smørgrav (stat(options.xauth_location, &st) == -1)) { 260219261079SEd Maste ssh_packet_send_debug(ssh, "No xauth program; cannot forward X11."); 2603af12a3e7SDag-Erling Smørgrav return 0; 2604af12a3e7SDag-Erling Smørgrav } 2605af12a3e7SDag-Erling Smørgrav if (s->display != NULL) { 2606af12a3e7SDag-Erling Smørgrav debug("X11 display already set."); 2607af12a3e7SDag-Erling Smørgrav return 0; 2608af12a3e7SDag-Erling Smørgrav } 26094f52dfbbSDag-Erling Smørgrav if (x11_create_display_inet(ssh, options.x11_display_offset, 2610a82e551fSDag-Erling Smørgrav options.x11_use_localhost, s->single_connection, 2611d4ecd108SDag-Erling Smørgrav &s->display_number, &s->x11_chanids) == -1) { 2612af12a3e7SDag-Erling Smørgrav debug("x11_create_display_inet failed."); 2613af12a3e7SDag-Erling Smørgrav return 0; 2614af12a3e7SDag-Erling Smørgrav } 2615d4ecd108SDag-Erling Smørgrav for (i = 0; s->x11_chanids[i] != -1; i++) { 26164f52dfbbSDag-Erling Smørgrav channel_register_cleanup(ssh, s->x11_chanids[i], 2617b74df5b2SDag-Erling Smørgrav session_close_single_x11, 0); 2618d4ecd108SDag-Erling Smørgrav } 2619af12a3e7SDag-Erling Smørgrav 2620af12a3e7SDag-Erling Smørgrav /* Set up a suitable value for the DISPLAY variable. */ 262119261079SEd Maste if (gethostname(hostname, sizeof(hostname)) == -1) 2622af12a3e7SDag-Erling Smørgrav fatal("gethostname: %.100s", strerror(errno)); 2623af12a3e7SDag-Erling Smørgrav /* 2624af12a3e7SDag-Erling Smørgrav * auth_display must be used as the displayname when the 2625af12a3e7SDag-Erling Smørgrav * authorization entry is added with xauth(1). This will be 2626af12a3e7SDag-Erling Smørgrav * different than the DISPLAY string for localhost displays. 2627af12a3e7SDag-Erling Smørgrav */ 2628af12a3e7SDag-Erling Smørgrav if (options.x11_use_localhost) { 2629a82e551fSDag-Erling Smørgrav snprintf(display, sizeof display, "localhost:%u.%u", 2630af12a3e7SDag-Erling Smørgrav s->display_number, s->screen); 2631a82e551fSDag-Erling Smørgrav snprintf(auth_display, sizeof auth_display, "unix:%u.%u", 2632af12a3e7SDag-Erling Smørgrav s->display_number, s->screen); 2633af12a3e7SDag-Erling Smørgrav s->display = xstrdup(display); 2634af12a3e7SDag-Erling Smørgrav s->auth_display = xstrdup(auth_display); 2635af12a3e7SDag-Erling Smørgrav } else { 2636989dd127SDag-Erling Smørgrav #ifdef IPADDR_IN_DISPLAY 2637989dd127SDag-Erling Smørgrav struct hostent *he; 2638989dd127SDag-Erling Smørgrav struct in_addr my_addr; 2639989dd127SDag-Erling Smørgrav 2640989dd127SDag-Erling Smørgrav he = gethostbyname(hostname); 2641989dd127SDag-Erling Smørgrav if (he == NULL) { 2642989dd127SDag-Erling Smørgrav error("Can't get IP address for X11 DISPLAY."); 264319261079SEd Maste ssh_packet_send_debug(ssh, "Can't get IP address for X11 DISPLAY."); 2644989dd127SDag-Erling Smørgrav return 0; 2645989dd127SDag-Erling Smørgrav } 2646989dd127SDag-Erling Smørgrav memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr)); 2647a82e551fSDag-Erling Smørgrav snprintf(display, sizeof display, "%.50s:%u.%u", inet_ntoa(my_addr), 2648989dd127SDag-Erling Smørgrav s->display_number, s->screen); 2649989dd127SDag-Erling Smørgrav #else 2650a82e551fSDag-Erling Smørgrav snprintf(display, sizeof display, "%.400s:%u.%u", hostname, 2651af12a3e7SDag-Erling Smørgrav s->display_number, s->screen); 2652989dd127SDag-Erling Smørgrav #endif 2653af12a3e7SDag-Erling Smørgrav s->display = xstrdup(display); 2654af12a3e7SDag-Erling Smørgrav s->auth_display = xstrdup(display); 2655af12a3e7SDag-Erling Smørgrav } 2656af12a3e7SDag-Erling Smørgrav 2657af12a3e7SDag-Erling Smørgrav return 1; 2658af12a3e7SDag-Erling Smørgrav } 2659af12a3e7SDag-Erling Smørgrav 2660af12a3e7SDag-Erling Smørgrav static void 26614f52dfbbSDag-Erling Smørgrav do_authenticated2(struct ssh *ssh, Authctxt *authctxt) 2662a04a10f8SKris Kennaway { 26634f52dfbbSDag-Erling Smørgrav server_loop2(ssh, authctxt); 26641ec0d754SDag-Erling Smørgrav } 26651ec0d754SDag-Erling Smørgrav 26661ec0d754SDag-Erling Smørgrav void 26674f52dfbbSDag-Erling Smørgrav do_cleanup(struct ssh *ssh, Authctxt *authctxt) 26681ec0d754SDag-Erling Smørgrav { 26691ec0d754SDag-Erling Smørgrav static int called = 0; 26701ec0d754SDag-Erling Smørgrav 26711ec0d754SDag-Erling Smørgrav debug("do_cleanup"); 26721ec0d754SDag-Erling Smørgrav 26731ec0d754SDag-Erling Smørgrav /* no cleanup if we're in the child for login shell */ 26741ec0d754SDag-Erling Smørgrav if (is_child) 26751ec0d754SDag-Erling Smørgrav return; 26761ec0d754SDag-Erling Smørgrav 26771ec0d754SDag-Erling Smørgrav /* avoid double cleanup */ 26781ec0d754SDag-Erling Smørgrav if (called) 26791ec0d754SDag-Erling Smørgrav return; 26801ec0d754SDag-Erling Smørgrav called = 1; 26811ec0d754SDag-Erling Smørgrav 2682d4af9e69SDag-Erling Smørgrav if (authctxt == NULL) 26831ec0d754SDag-Erling Smørgrav return; 2684d4af9e69SDag-Erling Smørgrav 2685d4af9e69SDag-Erling Smørgrav #ifdef USE_PAM 2686d4af9e69SDag-Erling Smørgrav if (options.use_pam) { 2687d4af9e69SDag-Erling Smørgrav sshpam_cleanup(); 2688d4af9e69SDag-Erling Smørgrav sshpam_thread_cleanup(); 2689d4af9e69SDag-Erling Smørgrav } 2690d4af9e69SDag-Erling Smørgrav #endif 2691d4af9e69SDag-Erling Smørgrav 2692d4af9e69SDag-Erling Smørgrav if (!authctxt->authenticated) 2693d4af9e69SDag-Erling Smørgrav return; 2694d4af9e69SDag-Erling Smørgrav 26951ec0d754SDag-Erling Smørgrav #ifdef KRB5 26961ec0d754SDag-Erling Smørgrav if (options.kerberos_ticket_cleanup && 26971ec0d754SDag-Erling Smørgrav authctxt->krb5_ctx) 26981ec0d754SDag-Erling Smørgrav krb5_cleanup_proc(authctxt); 2699cf2b5f3bSDag-Erling Smørgrav #endif 27001ec0d754SDag-Erling Smørgrav 27011ec0d754SDag-Erling Smørgrav #ifdef GSSAPI 2702ca86bcf2SDag-Erling Smørgrav if (options.gss_cleanup_creds) 27031ec0d754SDag-Erling Smørgrav ssh_gssapi_cleanup_creds(); 27041ec0d754SDag-Erling Smørgrav #endif 27051ec0d754SDag-Erling Smørgrav 27061ec0d754SDag-Erling Smørgrav /* remove agent socket */ 27071ec0d754SDag-Erling Smørgrav auth_sock_cleanup_proc(authctxt->pw); 27081ec0d754SDag-Erling Smørgrav 27094f52dfbbSDag-Erling Smørgrav /* remove userauth info */ 27104f52dfbbSDag-Erling Smørgrav if (auth_info_file != NULL) { 27114f52dfbbSDag-Erling Smørgrav temporarily_use_uid(authctxt->pw); 27124f52dfbbSDag-Erling Smørgrav unlink(auth_info_file); 27134f52dfbbSDag-Erling Smørgrav restore_uid(); 27144f52dfbbSDag-Erling Smørgrav free(auth_info_file); 27154f52dfbbSDag-Erling Smørgrav auth_info_file = NULL; 27164f52dfbbSDag-Erling Smørgrav } 27174f52dfbbSDag-Erling Smørgrav 27181ec0d754SDag-Erling Smørgrav /* 27191ec0d754SDag-Erling Smørgrav * Cleanup ptys/utmp only if privsep is disabled, 27201ec0d754SDag-Erling Smørgrav * or if running in monitor. 27211ec0d754SDag-Erling Smørgrav */ 27221ec0d754SDag-Erling Smørgrav if (!use_privsep || mm_is_monitor()) 27234f52dfbbSDag-Erling Smørgrav session_destroy_all(ssh, session_pty_cleanup2); 2724a04a10f8SKris Kennaway } 2725076ad2f8SDag-Erling Smørgrav 2726076ad2f8SDag-Erling Smørgrav /* Return a name for the remote host that fits inside utmp_size */ 2727076ad2f8SDag-Erling Smørgrav 2728076ad2f8SDag-Erling Smørgrav const char * 2729076ad2f8SDag-Erling Smørgrav session_get_remote_name_or_ip(struct ssh *ssh, u_int utmp_size, int use_dns) 2730076ad2f8SDag-Erling Smørgrav { 2731076ad2f8SDag-Erling Smørgrav const char *remote = ""; 2732076ad2f8SDag-Erling Smørgrav 2733076ad2f8SDag-Erling Smørgrav if (utmp_size > 0) 2734076ad2f8SDag-Erling Smørgrav remote = auth_get_canonical_hostname(ssh, use_dns); 2735076ad2f8SDag-Erling Smørgrav if (utmp_size == 0 || strlen(remote) > utmp_size) 2736076ad2f8SDag-Erling Smørgrav remote = ssh_remote_ipaddr(ssh); 2737076ad2f8SDag-Erling Smørgrav return remote; 2738076ad2f8SDag-Erling Smørgrav } 2739076ad2f8SDag-Erling Smørgrav 2740