1b15c8340SDag-Erling Smørgrav /* $OpenBSD: session.c,v 1.252 2010/03/07 11:57:13 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 #include <sys/param.h> 41333ee039SDag-Erling Smørgrav #ifdef HAVE_SYS_STAT_H 42333ee039SDag-Erling Smørgrav # include <sys/stat.h> 43333ee039SDag-Erling Smørgrav #endif 44333ee039SDag-Erling Smørgrav #include <sys/socket.h> 45333ee039SDag-Erling Smørgrav #include <sys/un.h> 46333ee039SDag-Erling Smørgrav #include <sys/wait.h> 47333ee039SDag-Erling Smørgrav 48333ee039SDag-Erling Smørgrav #include <arpa/inet.h> 49333ee039SDag-Erling Smørgrav 50333ee039SDag-Erling Smørgrav #include <errno.h> 51333ee039SDag-Erling Smørgrav #include <grp.h> 52333ee039SDag-Erling Smørgrav #ifdef HAVE_PATHS_H 53333ee039SDag-Erling Smørgrav #include <paths.h> 54333ee039SDag-Erling Smørgrav #endif 55333ee039SDag-Erling Smørgrav #include <pwd.h> 56333ee039SDag-Erling Smørgrav #include <signal.h> 57333ee039SDag-Erling Smørgrav #include <stdarg.h> 58333ee039SDag-Erling Smørgrav #include <stdio.h> 59333ee039SDag-Erling Smørgrav #include <stdlib.h> 60333ee039SDag-Erling Smørgrav #include <string.h> 61333ee039SDag-Erling Smørgrav #include <unistd.h> 62333ee039SDag-Erling Smørgrav 63d4af9e69SDag-Erling Smørgrav #include "openbsd-compat/sys-queue.h" 64333ee039SDag-Erling Smørgrav #include "xmalloc.h" 65a04a10f8SKris Kennaway #include "ssh.h" 66ca3176e7SBrian Feldman #include "ssh1.h" 67ca3176e7SBrian Feldman #include "ssh2.h" 68ca3176e7SBrian Feldman #include "sshpty.h" 69a04a10f8SKris Kennaway #include "packet.h" 70a04a10f8SKris Kennaway #include "buffer.h" 7121e764dfSDag-Erling Smørgrav #include "match.h" 72a04a10f8SKris Kennaway #include "uidswap.h" 73a04a10f8SKris Kennaway #include "compat.h" 74a04a10f8SKris Kennaway #include "channels.h" 75333ee039SDag-Erling Smørgrav #include "key.h" 76333ee039SDag-Erling Smørgrav #include "cipher.h" 77333ee039SDag-Erling Smørgrav #ifdef GSSAPI 78333ee039SDag-Erling Smørgrav #include "ssh-gss.h" 79333ee039SDag-Erling Smørgrav #endif 80333ee039SDag-Erling Smørgrav #include "hostfile.h" 81a04a10f8SKris Kennaway #include "auth.h" 82c2d3a559SKris Kennaway #include "auth-options.h" 83ca3176e7SBrian Feldman #include "pathnames.h" 84ca3176e7SBrian Feldman #include "log.h" 85ca3176e7SBrian Feldman #include "servconf.h" 86ca3176e7SBrian Feldman #include "sshlogin.h" 87ca3176e7SBrian Feldman #include "serverloop.h" 88ca3176e7SBrian Feldman #include "canohost.h" 89d4af9e69SDag-Erling Smørgrav #include "misc.h" 90ca3176e7SBrian Feldman #include "session.h" 91d4ecd108SDag-Erling Smørgrav #include "kex.h" 9280628bacSDag-Erling Smørgrav #include "monitor_wrap.h" 93d4af9e69SDag-Erling Smørgrav #include "sftp.h" 94a04a10f8SKris Kennaway 951ec0d754SDag-Erling Smørgrav #if defined(KRB5) && defined(USE_AFS) 961ec0d754SDag-Erling Smørgrav #include <kafs.h> 971ec0d754SDag-Erling Smørgrav #endif 981ec0d754SDag-Erling Smørgrav 99cce7d346SDag-Erling Smørgrav #define IS_INTERNAL_SFTP(c) \ 100cce7d346SDag-Erling Smørgrav (!strncmp(c, INTERNAL_SFTP_NAME, sizeof(INTERNAL_SFTP_NAME) - 1) && \ 101cce7d346SDag-Erling Smørgrav (c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\0' || \ 102cce7d346SDag-Erling Smørgrav c[sizeof(INTERNAL_SFTP_NAME) - 1] == ' ' || \ 103cce7d346SDag-Erling Smørgrav c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\t')) 104cce7d346SDag-Erling Smørgrav 105a04a10f8SKris Kennaway /* func */ 106a04a10f8SKris Kennaway 107a04a10f8SKris Kennaway Session *session_new(void); 108d4af9e69SDag-Erling Smørgrav void session_set_fds(Session *, int, int, int, int); 1091ec0d754SDag-Erling Smørgrav void session_pty_cleanup(Session *); 110af12a3e7SDag-Erling Smørgrav void session_proctitle(Session *); 111af12a3e7SDag-Erling Smørgrav int session_setup_x11fwd(Session *); 112d4af9e69SDag-Erling Smørgrav int do_exec_pty(Session *, const char *); 113d4af9e69SDag-Erling Smørgrav int do_exec_no_pty(Session *, const char *); 114d4af9e69SDag-Erling Smørgrav int do_exec(Session *, const char *); 115af12a3e7SDag-Erling Smørgrav void do_login(Session *, const char *); 116989dd127SDag-Erling Smørgrav #ifdef LOGIN_NEEDS_UTMPX 117989dd127SDag-Erling Smørgrav static void do_pre_login(Session *s); 118989dd127SDag-Erling Smørgrav #endif 119af12a3e7SDag-Erling Smørgrav void do_child(Session *, const char *); 120ca3176e7SBrian Feldman void do_motd(void); 121af12a3e7SDag-Erling Smørgrav int check_quietlogin(Session *, const char *); 122a04a10f8SKris Kennaway 123af12a3e7SDag-Erling Smørgrav static void do_authenticated1(Authctxt *); 124af12a3e7SDag-Erling Smørgrav static void do_authenticated2(Authctxt *); 125af12a3e7SDag-Erling Smørgrav 126af12a3e7SDag-Erling Smørgrav static int session_pty_req(Session *); 127a04a10f8SKris Kennaway 128a04a10f8SKris Kennaway /* import */ 129a04a10f8SKris Kennaway extern ServerOptions options; 130a04a10f8SKris Kennaway extern char *__progname; 131a04a10f8SKris Kennaway extern int log_stderr; 132a04a10f8SKris Kennaway extern int debug_flag; 133ca3176e7SBrian Feldman extern u_int utmp_len; 134c2d3a559SKris Kennaway extern int startup_pipe; 135ca3176e7SBrian Feldman extern void destroy_sensitive_data(void); 136cf2b5f3bSDag-Erling Smørgrav extern Buffer loginmsg; 137a04a10f8SKris Kennaway 138c2d3a559SKris Kennaway /* original command from peer. */ 139af12a3e7SDag-Erling Smørgrav const char *original_command = NULL; 140c2d3a559SKris Kennaway 141a04a10f8SKris Kennaway /* data */ 142d4af9e69SDag-Erling Smørgrav static int sessions_first_unused = -1; 143d4af9e69SDag-Erling Smørgrav static int sessions_nalloc = 0; 144d4af9e69SDag-Erling Smørgrav static Session *sessions = NULL; 145d4af9e69SDag-Erling Smørgrav 146d4af9e69SDag-Erling Smørgrav #define SUBSYSTEM_NONE 0 147d4af9e69SDag-Erling Smørgrav #define SUBSYSTEM_EXT 1 148d4af9e69SDag-Erling Smørgrav #define SUBSYSTEM_INT_SFTP 2 149b15c8340SDag-Erling Smørgrav #define SUBSYSTEM_INT_SFTP_ERROR 3 150a04a10f8SKris Kennaway 151c2d3a559SKris Kennaway #ifdef HAVE_LOGIN_CAP 15280628bacSDag-Erling Smørgrav login_cap_t *lc; 153c2d3a559SKris Kennaway #endif 154a04a10f8SKris Kennaway 1551ec0d754SDag-Erling Smørgrav static int is_child = 0; 1561ec0d754SDag-Erling Smørgrav 15780628bacSDag-Erling Smørgrav /* Name and directory of socket for authentication agent forwarding. */ 15880628bacSDag-Erling Smørgrav static char *auth_sock_name = NULL; 15980628bacSDag-Erling Smørgrav static char *auth_sock_dir = NULL; 16080628bacSDag-Erling Smørgrav 16180628bacSDag-Erling Smørgrav /* removes the agent forwarding socket */ 16280628bacSDag-Erling Smørgrav 16380628bacSDag-Erling Smørgrav static void 1641ec0d754SDag-Erling Smørgrav auth_sock_cleanup_proc(struct passwd *pw) 16580628bacSDag-Erling Smørgrav { 16680628bacSDag-Erling Smørgrav if (auth_sock_name != NULL) { 16780628bacSDag-Erling Smørgrav temporarily_use_uid(pw); 16880628bacSDag-Erling Smørgrav unlink(auth_sock_name); 16980628bacSDag-Erling Smørgrav rmdir(auth_sock_dir); 17080628bacSDag-Erling Smørgrav auth_sock_name = NULL; 17180628bacSDag-Erling Smørgrav restore_uid(); 17280628bacSDag-Erling Smørgrav } 17380628bacSDag-Erling Smørgrav } 17480628bacSDag-Erling Smørgrav 17580628bacSDag-Erling Smørgrav static int 17680628bacSDag-Erling Smørgrav auth_input_request_forwarding(struct passwd * pw) 17780628bacSDag-Erling Smørgrav { 17880628bacSDag-Erling Smørgrav Channel *nc; 179d4af9e69SDag-Erling Smørgrav int sock = -1; 18080628bacSDag-Erling Smørgrav struct sockaddr_un sunaddr; 18180628bacSDag-Erling Smørgrav 18280628bacSDag-Erling Smørgrav if (auth_sock_name != NULL) { 18380628bacSDag-Erling Smørgrav error("authentication forwarding requested twice."); 18480628bacSDag-Erling Smørgrav return 0; 18580628bacSDag-Erling Smørgrav } 18680628bacSDag-Erling Smørgrav 18780628bacSDag-Erling Smørgrav /* Temporarily drop privileged uid for mkdir/bind. */ 18880628bacSDag-Erling Smørgrav temporarily_use_uid(pw); 18980628bacSDag-Erling Smørgrav 19080628bacSDag-Erling Smørgrav /* Allocate a buffer for the socket name, and format the name. */ 191d4af9e69SDag-Erling Smørgrav auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX"); 19280628bacSDag-Erling Smørgrav 19380628bacSDag-Erling Smørgrav /* Create private directory for socket */ 19480628bacSDag-Erling Smørgrav if (mkdtemp(auth_sock_dir) == NULL) { 19580628bacSDag-Erling Smørgrav packet_send_debug("Agent forwarding disabled: " 19680628bacSDag-Erling Smørgrav "mkdtemp() failed: %.100s", strerror(errno)); 19780628bacSDag-Erling Smørgrav restore_uid(); 19880628bacSDag-Erling Smørgrav xfree(auth_sock_dir); 19980628bacSDag-Erling Smørgrav auth_sock_dir = NULL; 200d4af9e69SDag-Erling Smørgrav goto authsock_err; 20180628bacSDag-Erling Smørgrav } 202d4af9e69SDag-Erling Smørgrav 203d4af9e69SDag-Erling Smørgrav xasprintf(&auth_sock_name, "%s/agent.%ld", 20480628bacSDag-Erling Smørgrav auth_sock_dir, (long) getpid()); 20580628bacSDag-Erling Smørgrav 20680628bacSDag-Erling Smørgrav /* Create the socket. */ 20780628bacSDag-Erling Smørgrav sock = socket(AF_UNIX, SOCK_STREAM, 0); 208d4af9e69SDag-Erling Smørgrav if (sock < 0) { 209d4af9e69SDag-Erling Smørgrav error("socket: %.100s", strerror(errno)); 210d4af9e69SDag-Erling Smørgrav restore_uid(); 211d4af9e69SDag-Erling Smørgrav goto authsock_err; 212d4af9e69SDag-Erling Smørgrav } 21380628bacSDag-Erling Smørgrav 21480628bacSDag-Erling Smørgrav /* Bind it to the name. */ 21580628bacSDag-Erling Smørgrav memset(&sunaddr, 0, sizeof(sunaddr)); 21680628bacSDag-Erling Smørgrav sunaddr.sun_family = AF_UNIX; 21780628bacSDag-Erling Smørgrav strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path)); 21880628bacSDag-Erling Smørgrav 219d4af9e69SDag-Erling Smørgrav if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) { 220d4af9e69SDag-Erling Smørgrav error("bind: %.100s", strerror(errno)); 221d4af9e69SDag-Erling Smørgrav restore_uid(); 222d4af9e69SDag-Erling Smørgrav goto authsock_err; 223d4af9e69SDag-Erling Smørgrav } 22480628bacSDag-Erling Smørgrav 22580628bacSDag-Erling Smørgrav /* Restore the privileged uid. */ 22680628bacSDag-Erling Smørgrav restore_uid(); 22780628bacSDag-Erling Smørgrav 22880628bacSDag-Erling Smørgrav /* Start listening on the socket. */ 229d4af9e69SDag-Erling Smørgrav if (listen(sock, SSH_LISTEN_BACKLOG) < 0) { 230d4af9e69SDag-Erling Smørgrav error("listen: %.100s", strerror(errno)); 231d4af9e69SDag-Erling Smørgrav goto authsock_err; 232d4af9e69SDag-Erling Smørgrav } 23380628bacSDag-Erling Smørgrav 23480628bacSDag-Erling Smørgrav /* Allocate a channel for the authentication agent socket. */ 23580628bacSDag-Erling Smørgrav nc = channel_new("auth socket", 23680628bacSDag-Erling Smørgrav SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, 23780628bacSDag-Erling Smørgrav CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 238cf2b5f3bSDag-Erling Smørgrav 0, "auth socket", 1); 239cce7d346SDag-Erling Smørgrav nc->path = xstrdup(auth_sock_name); 24080628bacSDag-Erling Smørgrav return 1; 241d4af9e69SDag-Erling Smørgrav 242d4af9e69SDag-Erling Smørgrav authsock_err: 243d4af9e69SDag-Erling Smørgrav if (auth_sock_name != NULL) 244d4af9e69SDag-Erling Smørgrav xfree(auth_sock_name); 245d4af9e69SDag-Erling Smørgrav if (auth_sock_dir != NULL) { 246d4af9e69SDag-Erling Smørgrav rmdir(auth_sock_dir); 247d4af9e69SDag-Erling Smørgrav xfree(auth_sock_dir); 248d4af9e69SDag-Erling Smørgrav } 249d4af9e69SDag-Erling Smørgrav if (sock != -1) 250d4af9e69SDag-Erling Smørgrav close(sock); 251d4af9e69SDag-Erling Smørgrav auth_sock_name = NULL; 252d4af9e69SDag-Erling Smørgrav auth_sock_dir = NULL; 253d4af9e69SDag-Erling Smørgrav return 0; 25480628bacSDag-Erling Smørgrav } 25580628bacSDag-Erling Smørgrav 2561ec0d754SDag-Erling Smørgrav static void 2571ec0d754SDag-Erling Smørgrav display_loginmsg(void) 2581ec0d754SDag-Erling Smørgrav { 2591ec0d754SDag-Erling Smørgrav if (buffer_len(&loginmsg) > 0) { 2601ec0d754SDag-Erling Smørgrav buffer_append(&loginmsg, "\0", 1); 26121e764dfSDag-Erling Smørgrav printf("%s", (char *)buffer_ptr(&loginmsg)); 2621ec0d754SDag-Erling Smørgrav buffer_clear(&loginmsg); 2631ec0d754SDag-Erling Smørgrav } 2641ec0d754SDag-Erling Smørgrav } 26580628bacSDag-Erling Smørgrav 266ca3176e7SBrian Feldman void 267ca3176e7SBrian Feldman do_authenticated(Authctxt *authctxt) 268ca3176e7SBrian Feldman { 269e73e9afaSDag-Erling Smørgrav setproctitle("%s", authctxt->pw->pw_name); 270e73e9afaSDag-Erling Smørgrav 271ca3176e7SBrian Feldman /* setup the channel layer */ 272ca3176e7SBrian Feldman if (!no_port_forwarding_flag && options.allow_tcp_forwarding) 273ca3176e7SBrian Feldman channel_permit_all_opens(); 274ca3176e7SBrian Feldman 275b15c8340SDag-Erling Smørgrav auth_debug_send(); 276b15c8340SDag-Erling Smørgrav 277ca3176e7SBrian Feldman if (compat20) 278ca3176e7SBrian Feldman do_authenticated2(authctxt); 279ca3176e7SBrian Feldman else 280ca3176e7SBrian Feldman do_authenticated1(authctxt); 281e9fd63dfSBrian Feldman 2821ec0d754SDag-Erling Smørgrav do_cleanup(authctxt); 283a04a10f8SKris Kennaway } 284a04a10f8SKris Kennaway 285a04a10f8SKris Kennaway /* 286a04a10f8SKris Kennaway * Prepares for an interactive session. This is called after the user has 287a04a10f8SKris Kennaway * been successfully authenticated. During this message exchange, pseudo 288a04a10f8SKris Kennaway * terminals are allocated, X11, TCP/IP, and authentication agent forwardings 289a04a10f8SKris Kennaway * are requested, etc. 290a04a10f8SKris Kennaway */ 291af12a3e7SDag-Erling Smørgrav static void 292ca3176e7SBrian Feldman do_authenticated1(Authctxt *authctxt) 293a04a10f8SKris Kennaway { 294a04a10f8SKris Kennaway Session *s; 295a04a10f8SKris Kennaway char *command; 296af12a3e7SDag-Erling Smørgrav int success, type, screen_flag; 297a82e551fSDag-Erling Smørgrav int enable_compression_after_reply = 0; 298a82e551fSDag-Erling Smørgrav u_int proto_len, data_len, dlen, compression_level = 0; 299a04a10f8SKris Kennaway 300a04a10f8SKris Kennaway s = session_new(); 301aa49c926SDag-Erling Smørgrav if (s == NULL) { 302aa49c926SDag-Erling Smørgrav error("no more sessions"); 303aa49c926SDag-Erling Smørgrav return; 304aa49c926SDag-Erling Smørgrav } 305af12a3e7SDag-Erling Smørgrav s->authctxt = authctxt; 306ca3176e7SBrian Feldman s->pw = authctxt->pw; 307c2d3a559SKris Kennaway 308a04a10f8SKris Kennaway /* 309a04a10f8SKris Kennaway * We stay in this loop until the client requests to execute a shell 310a04a10f8SKris Kennaway * or a command. 311a04a10f8SKris Kennaway */ 312a04a10f8SKris Kennaway for (;;) { 313ca3176e7SBrian Feldman success = 0; 314a04a10f8SKris Kennaway 315a04a10f8SKris Kennaway /* Get a packet from the client. */ 316af12a3e7SDag-Erling Smørgrav type = packet_read(); 317a04a10f8SKris Kennaway 318a04a10f8SKris Kennaway /* Process the packet. */ 319a04a10f8SKris Kennaway switch (type) { 320a04a10f8SKris Kennaway case SSH_CMSG_REQUEST_COMPRESSION: 321a04a10f8SKris Kennaway compression_level = packet_get_int(); 322af12a3e7SDag-Erling Smørgrav packet_check_eom(); 323a04a10f8SKris Kennaway if (compression_level < 1 || compression_level > 9) { 32421e764dfSDag-Erling Smørgrav packet_send_debug("Received invalid compression level %d.", 325a04a10f8SKris Kennaway compression_level); 326a04a10f8SKris Kennaway break; 327a04a10f8SKris Kennaway } 328d4ecd108SDag-Erling Smørgrav if (options.compression == COMP_NONE) { 32980628bacSDag-Erling Smørgrav debug2("compression disabled"); 33080628bacSDag-Erling Smørgrav break; 33180628bacSDag-Erling Smørgrav } 332a04a10f8SKris Kennaway /* Enable compression after we have responded with SUCCESS. */ 333a04a10f8SKris Kennaway enable_compression_after_reply = 1; 334a04a10f8SKris Kennaway success = 1; 335a04a10f8SKris Kennaway break; 336a04a10f8SKris Kennaway 337a04a10f8SKris Kennaway case SSH_CMSG_REQUEST_PTY: 338af12a3e7SDag-Erling Smørgrav success = session_pty_req(s); 339a04a10f8SKris Kennaway break; 340a04a10f8SKris Kennaway 341a04a10f8SKris Kennaway case SSH_CMSG_X11_REQUEST_FORWARDING: 342a04a10f8SKris Kennaway s->auth_proto = packet_get_string(&proto_len); 343a04a10f8SKris Kennaway s->auth_data = packet_get_string(&data_len); 344a04a10f8SKris Kennaway 345ca3176e7SBrian Feldman screen_flag = packet_get_protocol_flags() & 346ca3176e7SBrian Feldman SSH_PROTOFLAG_SCREEN_NUMBER; 347ca3176e7SBrian Feldman debug2("SSH_PROTOFLAG_SCREEN_NUMBER: %d", screen_flag); 348ca3176e7SBrian Feldman 349ca3176e7SBrian Feldman if (packet_remaining() == 4) { 350ca3176e7SBrian Feldman if (!screen_flag) 351ca3176e7SBrian Feldman debug2("Buggy client: " 352ca3176e7SBrian Feldman "X11 screen flag missing"); 353a04a10f8SKris Kennaway s->screen = packet_get_int(); 354ca3176e7SBrian Feldman } else { 355a04a10f8SKris Kennaway s->screen = 0; 356ca3176e7SBrian Feldman } 357af12a3e7SDag-Erling Smørgrav packet_check_eom(); 358af12a3e7SDag-Erling Smørgrav success = session_setup_x11fwd(s); 359af12a3e7SDag-Erling Smørgrav if (!success) { 360af12a3e7SDag-Erling Smørgrav xfree(s->auth_proto); 361af12a3e7SDag-Erling Smørgrav xfree(s->auth_data); 362af12a3e7SDag-Erling Smørgrav s->auth_proto = NULL; 363af12a3e7SDag-Erling Smørgrav s->auth_data = NULL; 364a04a10f8SKris Kennaway } 365a04a10f8SKris Kennaway break; 366a04a10f8SKris Kennaway 367a04a10f8SKris Kennaway case SSH_CMSG_AGENT_REQUEST_FORWARDING: 368d4af9e69SDag-Erling Smørgrav if (!options.allow_agent_forwarding || 369d4af9e69SDag-Erling Smørgrav no_agent_forwarding_flag || compat13) { 370a04a10f8SKris Kennaway debug("Authentication agent forwarding not permitted for this authentication."); 371a04a10f8SKris Kennaway break; 372a04a10f8SKris Kennaway } 373a04a10f8SKris Kennaway debug("Received authentication agent forwarding request."); 374ca3176e7SBrian Feldman success = auth_input_request_forwarding(s->pw); 375a04a10f8SKris Kennaway break; 376a04a10f8SKris Kennaway 377a04a10f8SKris Kennaway case SSH_CMSG_PORT_FORWARD_REQUEST: 378a04a10f8SKris Kennaway if (no_port_forwarding_flag) { 379a04a10f8SKris Kennaway debug("Port forwarding not permitted for this authentication."); 380a04a10f8SKris Kennaway break; 381a04a10f8SKris Kennaway } 38209958426SBrian Feldman if (!options.allow_tcp_forwarding) { 38309958426SBrian Feldman debug("Port forwarding not permitted."); 38409958426SBrian Feldman break; 38509958426SBrian Feldman } 386a04a10f8SKris Kennaway debug("Received TCP/IP port forwarding request."); 387333ee039SDag-Erling Smørgrav if (channel_input_port_forward_request(s->pw->pw_uid == 0, 388333ee039SDag-Erling Smørgrav options.gateway_ports) < 0) { 389333ee039SDag-Erling Smørgrav debug("Port forwarding failed."); 390333ee039SDag-Erling Smørgrav break; 391333ee039SDag-Erling Smørgrav } 392a04a10f8SKris Kennaway success = 1; 393a04a10f8SKris Kennaway break; 394a04a10f8SKris Kennaway 395a04a10f8SKris Kennaway case SSH_CMSG_MAX_PACKET_SIZE: 396a04a10f8SKris Kennaway if (packet_set_maxsize(packet_get_int()) > 0) 397a04a10f8SKris Kennaway success = 1; 398a04a10f8SKris Kennaway break; 399a04a10f8SKris Kennaway 400a04a10f8SKris Kennaway case SSH_CMSG_EXEC_SHELL: 401a04a10f8SKris Kennaway case SSH_CMSG_EXEC_CMD: 402a04a10f8SKris Kennaway if (type == SSH_CMSG_EXEC_CMD) { 403a04a10f8SKris Kennaway command = packet_get_string(&dlen); 404a04a10f8SKris Kennaway debug("Exec command '%.500s'", command); 405d4af9e69SDag-Erling Smørgrav if (do_exec(s, command) != 0) 406d4af9e69SDag-Erling Smørgrav packet_disconnect( 407d4af9e69SDag-Erling Smørgrav "command execution failed"); 408a04a10f8SKris Kennaway xfree(command); 409af12a3e7SDag-Erling Smørgrav } else { 410d4af9e69SDag-Erling Smørgrav if (do_exec(s, NULL) != 0) 411d4af9e69SDag-Erling Smørgrav packet_disconnect( 412d4af9e69SDag-Erling Smørgrav "shell execution failed"); 413af12a3e7SDag-Erling Smørgrav } 414af12a3e7SDag-Erling Smørgrav packet_check_eom(); 415af12a3e7SDag-Erling Smørgrav session_close(s); 416a04a10f8SKris Kennaway return; 417a04a10f8SKris Kennaway 418a04a10f8SKris Kennaway default: 419a04a10f8SKris Kennaway /* 420a04a10f8SKris Kennaway * Any unknown messages in this phase are ignored, 421a04a10f8SKris Kennaway * and a failure message is returned. 422a04a10f8SKris Kennaway */ 423cf2b5f3bSDag-Erling Smørgrav logit("Unknown packet type received after authentication: %d", type); 424a04a10f8SKris Kennaway } 425a04a10f8SKris Kennaway packet_start(success ? SSH_SMSG_SUCCESS : SSH_SMSG_FAILURE); 426a04a10f8SKris Kennaway packet_send(); 427a04a10f8SKris Kennaway packet_write_wait(); 428a04a10f8SKris Kennaway 429a04a10f8SKris Kennaway /* Enable compression now that we have replied if appropriate. */ 430a04a10f8SKris Kennaway if (enable_compression_after_reply) { 431a04a10f8SKris Kennaway enable_compression_after_reply = 0; 432a04a10f8SKris Kennaway packet_start_compression(compression_level); 433a04a10f8SKris Kennaway } 434a04a10f8SKris Kennaway } 435a04a10f8SKris Kennaway } 436a04a10f8SKris Kennaway 437d4af9e69SDag-Erling Smørgrav #define USE_PIPES 438a04a10f8SKris Kennaway /* 439a04a10f8SKris Kennaway * This is called to fork and execute a command when we have no tty. This 440a04a10f8SKris Kennaway * will call do_child from the child, and server_loop from the parent after 441a04a10f8SKris Kennaway * setting up file descriptors and such. 442a04a10f8SKris Kennaway */ 443d4af9e69SDag-Erling Smørgrav int 444ca3176e7SBrian Feldman do_exec_no_pty(Session *s, const char *command) 445a04a10f8SKris Kennaway { 44680628bacSDag-Erling Smørgrav pid_t pid; 447a04a10f8SKris Kennaway 448a04a10f8SKris Kennaway #ifdef USE_PIPES 449a04a10f8SKris Kennaway int pin[2], pout[2], perr[2]; 450d4af9e69SDag-Erling Smørgrav 451a04a10f8SKris Kennaway /* Allocate pipes for communicating with the program. */ 452d4af9e69SDag-Erling Smørgrav if (pipe(pin) < 0) { 453d4af9e69SDag-Erling Smørgrav error("%s: pipe in: %.100s", __func__, strerror(errno)); 454d4af9e69SDag-Erling Smørgrav return -1; 455d4af9e69SDag-Erling Smørgrav } 456d4af9e69SDag-Erling Smørgrav if (pipe(pout) < 0) { 457d4af9e69SDag-Erling Smørgrav error("%s: pipe out: %.100s", __func__, strerror(errno)); 458d4af9e69SDag-Erling Smørgrav close(pin[0]); 459d4af9e69SDag-Erling Smørgrav close(pin[1]); 460d4af9e69SDag-Erling Smørgrav return -1; 461d4af9e69SDag-Erling Smørgrav } 462d4af9e69SDag-Erling Smørgrav if (pipe(perr) < 0) { 463d4af9e69SDag-Erling Smørgrav error("%s: pipe err: %.100s", __func__, strerror(errno)); 464d4af9e69SDag-Erling Smørgrav close(pin[0]); 465d4af9e69SDag-Erling Smørgrav close(pin[1]); 466d4af9e69SDag-Erling Smørgrav close(pout[0]); 467d4af9e69SDag-Erling Smørgrav close(pout[1]); 468d4af9e69SDag-Erling Smørgrav return -1; 469d4af9e69SDag-Erling Smørgrav } 470d4af9e69SDag-Erling Smørgrav #else 471a04a10f8SKris Kennaway int inout[2], err[2]; 472d4af9e69SDag-Erling Smørgrav 473a04a10f8SKris Kennaway /* Uses socket pairs to communicate with the program. */ 474d4af9e69SDag-Erling Smørgrav if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0) { 475d4af9e69SDag-Erling Smørgrav error("%s: socketpair #1: %.100s", __func__, strerror(errno)); 476d4af9e69SDag-Erling Smørgrav return -1; 477d4af9e69SDag-Erling Smørgrav } 478d4af9e69SDag-Erling Smørgrav if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) { 479d4af9e69SDag-Erling Smørgrav error("%s: socketpair #2: %.100s", __func__, strerror(errno)); 480d4af9e69SDag-Erling Smørgrav close(inout[0]); 481d4af9e69SDag-Erling Smørgrav close(inout[1]); 482d4af9e69SDag-Erling Smørgrav return -1; 483d4af9e69SDag-Erling Smørgrav } 484d4af9e69SDag-Erling Smørgrav #endif 485d4af9e69SDag-Erling Smørgrav 486a04a10f8SKris Kennaway if (s == NULL) 487a04a10f8SKris Kennaway fatal("do_exec_no_pty: no session"); 488a04a10f8SKris Kennaway 489a04a10f8SKris Kennaway session_proctitle(s); 490a04a10f8SKris Kennaway 491a04a10f8SKris Kennaway /* Fork the child. */ 492d4af9e69SDag-Erling Smørgrav switch ((pid = fork())) { 493d4af9e69SDag-Erling Smørgrav case -1: 494d4af9e69SDag-Erling Smørgrav error("%s: fork: %.100s", __func__, strerror(errno)); 495d4af9e69SDag-Erling Smørgrav #ifdef USE_PIPES 496d4af9e69SDag-Erling Smørgrav close(pin[0]); 497d4af9e69SDag-Erling Smørgrav close(pin[1]); 498d4af9e69SDag-Erling Smørgrav close(pout[0]); 499d4af9e69SDag-Erling Smørgrav close(pout[1]); 500d4af9e69SDag-Erling Smørgrav close(perr[0]); 501d4af9e69SDag-Erling Smørgrav close(perr[1]); 502d4af9e69SDag-Erling Smørgrav #else 503d4af9e69SDag-Erling Smørgrav close(inout[0]); 504d4af9e69SDag-Erling Smørgrav close(inout[1]); 505d4af9e69SDag-Erling Smørgrav close(err[0]); 506d4af9e69SDag-Erling Smørgrav close(err[1]); 507d4af9e69SDag-Erling Smørgrav #endif 508d4af9e69SDag-Erling Smørgrav return -1; 509d4af9e69SDag-Erling Smørgrav case 0: 5101ec0d754SDag-Erling Smørgrav is_child = 1; 511f388f5efSDag-Erling Smørgrav 512a04a10f8SKris Kennaway /* Child. Reinitialize the log since the pid has changed. */ 513d4af9e69SDag-Erling Smørgrav log_init(__progname, options.log_level, 514d4af9e69SDag-Erling Smørgrav options.log_facility, log_stderr); 515a04a10f8SKris Kennaway 516a04a10f8SKris Kennaway /* 517a04a10f8SKris Kennaway * Create a new session and process group since the 4.4BSD 518a04a10f8SKris Kennaway * setlogin() affects the entire process group. 519a04a10f8SKris Kennaway */ 520a04a10f8SKris Kennaway if (setsid() < 0) 521a04a10f8SKris Kennaway error("setsid failed: %.100s", strerror(errno)); 522a04a10f8SKris Kennaway 523a04a10f8SKris Kennaway #ifdef USE_PIPES 524a04a10f8SKris Kennaway /* 525a04a10f8SKris Kennaway * Redirect stdin. We close the parent side of the socket 526a04a10f8SKris Kennaway * pair, and make the child side the standard input. 527a04a10f8SKris Kennaway */ 528a04a10f8SKris Kennaway close(pin[1]); 529a04a10f8SKris Kennaway if (dup2(pin[0], 0) < 0) 530a04a10f8SKris Kennaway perror("dup2 stdin"); 531a04a10f8SKris Kennaway close(pin[0]); 532a04a10f8SKris Kennaway 533a04a10f8SKris Kennaway /* Redirect stdout. */ 534a04a10f8SKris Kennaway close(pout[0]); 535a04a10f8SKris Kennaway if (dup2(pout[1], 1) < 0) 536a04a10f8SKris Kennaway perror("dup2 stdout"); 537a04a10f8SKris Kennaway close(pout[1]); 538a04a10f8SKris Kennaway 539a04a10f8SKris Kennaway /* Redirect stderr. */ 540a04a10f8SKris Kennaway close(perr[0]); 541a04a10f8SKris Kennaway if (dup2(perr[1], 2) < 0) 542a04a10f8SKris Kennaway perror("dup2 stderr"); 543a04a10f8SKris Kennaway close(perr[1]); 544d4af9e69SDag-Erling Smørgrav #else 545a04a10f8SKris Kennaway /* 546a04a10f8SKris Kennaway * Redirect stdin, stdout, and stderr. Stdin and stdout will 547a04a10f8SKris Kennaway * use the same socket, as some programs (particularly rdist) 548a04a10f8SKris Kennaway * seem to depend on it. 549a04a10f8SKris Kennaway */ 550a04a10f8SKris Kennaway close(inout[1]); 551a04a10f8SKris Kennaway close(err[1]); 552a04a10f8SKris Kennaway if (dup2(inout[0], 0) < 0) /* stdin */ 553a04a10f8SKris Kennaway perror("dup2 stdin"); 554d4af9e69SDag-Erling Smørgrav if (dup2(inout[0], 1) < 0) /* stdout (same as stdin) */ 555a04a10f8SKris Kennaway perror("dup2 stdout"); 556d4af9e69SDag-Erling Smørgrav close(inout[0]); 557a04a10f8SKris Kennaway if (dup2(err[0], 2) < 0) /* stderr */ 558a04a10f8SKris Kennaway perror("dup2 stderr"); 559d4af9e69SDag-Erling Smørgrav close(err[0]); 560d4af9e69SDag-Erling Smørgrav #endif 561d4af9e69SDag-Erling Smørgrav 562a04a10f8SKris Kennaway 563f388f5efSDag-Erling Smørgrav #ifdef _UNICOS 564f388f5efSDag-Erling Smørgrav cray_init_job(s->pw); /* set up cray jid and tmpdir */ 565f388f5efSDag-Erling Smørgrav #endif 566f388f5efSDag-Erling Smørgrav 567a04a10f8SKris Kennaway /* Do processing for the child (exec command etc). */ 568ca3176e7SBrian Feldman do_child(s, command); 569a04a10f8SKris Kennaway /* NOTREACHED */ 570d4af9e69SDag-Erling Smørgrav default: 571d4af9e69SDag-Erling Smørgrav break; 572a04a10f8SKris Kennaway } 573d4af9e69SDag-Erling Smørgrav 574f388f5efSDag-Erling Smørgrav #ifdef _UNICOS 575f388f5efSDag-Erling Smørgrav signal(WJSIGNAL, cray_job_termination_handler); 576f388f5efSDag-Erling Smørgrav #endif /* _UNICOS */ 577989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN 578989dd127SDag-Erling Smørgrav cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); 579989dd127SDag-Erling Smørgrav #endif 580d4af9e69SDag-Erling Smørgrav 581a04a10f8SKris Kennaway s->pid = pid; 582ca3176e7SBrian Feldman /* Set interactive/non-interactive mode. */ 583ca3176e7SBrian Feldman packet_set_interactive(s->display != NULL); 584d4af9e69SDag-Erling Smørgrav 585d4af9e69SDag-Erling Smørgrav /* 586d4af9e69SDag-Erling Smørgrav * Clear loginmsg, since it's the child's responsibility to display 587d4af9e69SDag-Erling Smørgrav * it to the user, otherwise multiple sessions may accumulate 588d4af9e69SDag-Erling Smørgrav * multiple copies of the login messages. 589d4af9e69SDag-Erling Smørgrav */ 590d4af9e69SDag-Erling Smørgrav buffer_clear(&loginmsg); 591d4af9e69SDag-Erling Smørgrav 592a04a10f8SKris Kennaway #ifdef USE_PIPES 593a04a10f8SKris Kennaway /* We are the parent. Close the child sides of the pipes. */ 594a04a10f8SKris Kennaway close(pin[0]); 595a04a10f8SKris Kennaway close(pout[1]); 596a04a10f8SKris Kennaway close(perr[1]); 597a04a10f8SKris Kennaway 598a04a10f8SKris Kennaway if (compat20) { 59921e764dfSDag-Erling Smørgrav if (s->is_subsystem) { 60021e764dfSDag-Erling Smørgrav close(perr[0]); 60121e764dfSDag-Erling Smørgrav perr[0] = -1; 60221e764dfSDag-Erling Smørgrav } 603d4af9e69SDag-Erling Smørgrav session_set_fds(s, pin[1], pout[0], perr[0], 0); 604a04a10f8SKris Kennaway } else { 605a04a10f8SKris Kennaway /* Enter the interactive session. */ 606a04a10f8SKris Kennaway server_loop(pid, pin[1], pout[0], perr[0]); 607ca3176e7SBrian Feldman /* server_loop has closed pin[1], pout[0], and perr[0]. */ 608a04a10f8SKris Kennaway } 609d4af9e69SDag-Erling Smørgrav #else 610a04a10f8SKris Kennaway /* We are the parent. Close the child sides of the socket pairs. */ 611a04a10f8SKris Kennaway close(inout[0]); 612a04a10f8SKris Kennaway close(err[0]); 613a04a10f8SKris Kennaway 614a04a10f8SKris Kennaway /* 615a04a10f8SKris Kennaway * Enter the interactive session. Note: server_loop must be able to 616a04a10f8SKris Kennaway * handle the case that fdin and fdout are the same. 617a04a10f8SKris Kennaway */ 618a04a10f8SKris Kennaway if (compat20) { 619d4af9e69SDag-Erling Smørgrav session_set_fds(s, inout[1], inout[1], 620d4af9e69SDag-Erling Smørgrav s->is_subsystem ? -1 : err[1], 0); 621d4af9e69SDag-Erling Smørgrav if (s->is_subsystem) 622d4af9e69SDag-Erling Smørgrav close(err[1]); 623a04a10f8SKris Kennaway } else { 624a04a10f8SKris Kennaway server_loop(pid, inout[1], inout[1], err[1]); 625a04a10f8SKris Kennaway /* server_loop has closed inout[1] and err[1]. */ 626a04a10f8SKris Kennaway } 627d4af9e69SDag-Erling Smørgrav #endif 628d4af9e69SDag-Erling Smørgrav return 0; 629a04a10f8SKris Kennaway } 630a04a10f8SKris Kennaway 631a04a10f8SKris Kennaway /* 632a04a10f8SKris Kennaway * This is called to fork and execute a command when we have a tty. This 633a04a10f8SKris Kennaway * will call do_child from the child, and server_loop from the parent after 634a04a10f8SKris Kennaway * setting up file descriptors, controlling tty, updating wtmp, utmp, 635a04a10f8SKris Kennaway * lastlog, and other such operations. 636a04a10f8SKris Kennaway */ 637d4af9e69SDag-Erling Smørgrav int 638ca3176e7SBrian Feldman do_exec_pty(Session *s, const char *command) 639a04a10f8SKris Kennaway { 640a04a10f8SKris Kennaway int fdout, ptyfd, ttyfd, ptymaster; 641a04a10f8SKris Kennaway pid_t pid; 642a04a10f8SKris Kennaway 643a04a10f8SKris Kennaway if (s == NULL) 644a04a10f8SKris Kennaway fatal("do_exec_pty: no session"); 645a04a10f8SKris Kennaway ptyfd = s->ptyfd; 646a04a10f8SKris Kennaway ttyfd = s->ttyfd; 647a04a10f8SKris Kennaway 648d4af9e69SDag-Erling Smørgrav /* 649d4af9e69SDag-Erling Smørgrav * Create another descriptor of the pty master side for use as the 650d4af9e69SDag-Erling Smørgrav * standard input. We could use the original descriptor, but this 651d4af9e69SDag-Erling Smørgrav * simplifies code in server_loop. The descriptor is bidirectional. 652d4af9e69SDag-Erling Smørgrav * Do this before forking (and cleanup in the child) so as to 653d4af9e69SDag-Erling Smørgrav * detect and gracefully fail out-of-fd conditions. 654d4af9e69SDag-Erling Smørgrav */ 655d4af9e69SDag-Erling Smørgrav if ((fdout = dup(ptyfd)) < 0) { 656d4af9e69SDag-Erling Smørgrav error("%s: dup #1: %s", __func__, strerror(errno)); 657d4af9e69SDag-Erling Smørgrav close(ttyfd); 658d4af9e69SDag-Erling Smørgrav close(ptyfd); 659d4af9e69SDag-Erling Smørgrav return -1; 660cf2b5f3bSDag-Erling Smørgrav } 661d4af9e69SDag-Erling Smørgrav /* we keep a reference to the pty master */ 662d4af9e69SDag-Erling Smørgrav if ((ptymaster = dup(ptyfd)) < 0) { 663d4af9e69SDag-Erling Smørgrav error("%s: dup #2: %s", __func__, strerror(errno)); 664d4af9e69SDag-Erling Smørgrav close(ttyfd); 665d4af9e69SDag-Erling Smørgrav close(ptyfd); 666d4af9e69SDag-Erling Smørgrav close(fdout); 667d4af9e69SDag-Erling Smørgrav return -1; 668d4af9e69SDag-Erling Smørgrav } 66909958426SBrian Feldman 670a04a10f8SKris Kennaway /* Fork the child. */ 671d4af9e69SDag-Erling Smørgrav switch ((pid = fork())) { 672d4af9e69SDag-Erling Smørgrav case -1: 673d4af9e69SDag-Erling Smørgrav error("%s: fork: %.100s", __func__, strerror(errno)); 674d4af9e69SDag-Erling Smørgrav close(fdout); 675d4af9e69SDag-Erling Smørgrav close(ptymaster); 676d4af9e69SDag-Erling Smørgrav close(ttyfd); 677d4af9e69SDag-Erling Smørgrav close(ptyfd); 678d4af9e69SDag-Erling Smørgrav return -1; 679d4af9e69SDag-Erling Smørgrav case 0: 6801ec0d754SDag-Erling Smørgrav is_child = 1; 681af12a3e7SDag-Erling Smørgrav 682d4af9e69SDag-Erling Smørgrav close(fdout); 683d4af9e69SDag-Erling Smørgrav close(ptymaster); 684d4af9e69SDag-Erling Smørgrav 685c2d3a559SKris Kennaway /* Child. Reinitialize the log because the pid has changed. */ 686d4af9e69SDag-Erling Smørgrav log_init(__progname, options.log_level, 687d4af9e69SDag-Erling Smørgrav options.log_facility, log_stderr); 688a04a10f8SKris Kennaway /* Close the master side of the pseudo tty. */ 689a04a10f8SKris Kennaway close(ptyfd); 690a04a10f8SKris Kennaway 691a04a10f8SKris Kennaway /* Make the pseudo tty our controlling tty. */ 692a04a10f8SKris Kennaway pty_make_controlling_tty(&ttyfd, s->tty); 693a04a10f8SKris Kennaway 694af12a3e7SDag-Erling Smørgrav /* Redirect stdin/stdout/stderr from the pseudo tty. */ 695af12a3e7SDag-Erling Smørgrav if (dup2(ttyfd, 0) < 0) 696af12a3e7SDag-Erling Smørgrav error("dup2 stdin: %s", strerror(errno)); 697af12a3e7SDag-Erling Smørgrav if (dup2(ttyfd, 1) < 0) 698af12a3e7SDag-Erling Smørgrav error("dup2 stdout: %s", strerror(errno)); 699af12a3e7SDag-Erling Smørgrav if (dup2(ttyfd, 2) < 0) 700af12a3e7SDag-Erling Smørgrav error("dup2 stderr: %s", strerror(errno)); 701a04a10f8SKris Kennaway 702a04a10f8SKris Kennaway /* Close the extra descriptor for the pseudo tty. */ 703a04a10f8SKris Kennaway close(ttyfd); 704a04a10f8SKris Kennaway 705c2d3a559SKris Kennaway /* record login, etc. similar to login(1) */ 706989dd127SDag-Erling Smørgrav #ifndef HAVE_OSF_SIA 707f388f5efSDag-Erling Smørgrav if (!(options.use_login && command == NULL)) { 708f388f5efSDag-Erling Smørgrav #ifdef _UNICOS 709f388f5efSDag-Erling Smørgrav cray_init_job(s->pw); /* set up cray jid and tmpdir */ 710f388f5efSDag-Erling Smørgrav #endif /* _UNICOS */ 711ca3176e7SBrian Feldman do_login(s, command); 712f388f5efSDag-Erling Smørgrav } 713989dd127SDag-Erling Smørgrav # ifdef LOGIN_NEEDS_UTMPX 714989dd127SDag-Erling Smørgrav else 715989dd127SDag-Erling Smørgrav do_pre_login(s); 716989dd127SDag-Erling Smørgrav # endif 717989dd127SDag-Erling Smørgrav #endif 718d4af9e69SDag-Erling Smørgrav /* 719d4af9e69SDag-Erling Smørgrav * Do common processing for the child, such as execing 720d4af9e69SDag-Erling Smørgrav * the command. 721d4af9e69SDag-Erling Smørgrav */ 722ca3176e7SBrian Feldman do_child(s, command); 723a04a10f8SKris Kennaway /* NOTREACHED */ 724d4af9e69SDag-Erling Smørgrav default: 725d4af9e69SDag-Erling Smørgrav break; 726a04a10f8SKris Kennaway } 727d4af9e69SDag-Erling Smørgrav 728f388f5efSDag-Erling Smørgrav #ifdef _UNICOS 729f388f5efSDag-Erling Smørgrav signal(WJSIGNAL, cray_job_termination_handler); 730f388f5efSDag-Erling Smørgrav #endif /* _UNICOS */ 731989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN 732989dd127SDag-Erling Smørgrav cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); 733989dd127SDag-Erling Smørgrav #endif 734d4af9e69SDag-Erling Smørgrav 735a04a10f8SKris Kennaway s->pid = pid; 736a04a10f8SKris Kennaway 737a04a10f8SKris Kennaway /* Parent. Close the slave side of the pseudo tty. */ 738a04a10f8SKris Kennaway close(ttyfd); 739a04a10f8SKris Kennaway 740a04a10f8SKris Kennaway /* Enter interactive session. */ 741d4af9e69SDag-Erling Smørgrav s->ptymaster = ptymaster; 742ca3176e7SBrian Feldman packet_set_interactive(1); 743a04a10f8SKris Kennaway if (compat20) { 744d4af9e69SDag-Erling Smørgrav session_set_fds(s, ptyfd, fdout, -1, 1); 745a04a10f8SKris Kennaway } else { 746a04a10f8SKris Kennaway server_loop(pid, ptyfd, fdout, -1); 747a04a10f8SKris Kennaway /* server_loop _has_ closed ptyfd and fdout. */ 748a04a10f8SKris Kennaway } 749d4af9e69SDag-Erling Smørgrav return 0; 750a04a10f8SKris Kennaway } 751a04a10f8SKris Kennaway 752989dd127SDag-Erling Smørgrav #ifdef LOGIN_NEEDS_UTMPX 753989dd127SDag-Erling Smørgrav static void 754989dd127SDag-Erling Smørgrav do_pre_login(Session *s) 755989dd127SDag-Erling Smørgrav { 756989dd127SDag-Erling Smørgrav socklen_t fromlen; 757989dd127SDag-Erling Smørgrav struct sockaddr_storage from; 758989dd127SDag-Erling Smørgrav pid_t pid = getpid(); 759989dd127SDag-Erling Smørgrav 760989dd127SDag-Erling Smørgrav /* 761989dd127SDag-Erling Smørgrav * Get IP address of client. If the connection is not a socket, let 762989dd127SDag-Erling Smørgrav * the address be 0.0.0.0. 763989dd127SDag-Erling Smørgrav */ 764989dd127SDag-Erling Smørgrav memset(&from, 0, sizeof(from)); 765989dd127SDag-Erling Smørgrav fromlen = sizeof(from); 7667ac32603SHajimu UMEMOTO if (packet_connection_is_on_socket()) { 767989dd127SDag-Erling Smørgrav if (getpeername(packet_get_connection_in(), 768989dd127SDag-Erling Smørgrav (struct sockaddr *)&from, &fromlen) < 0) { 769989dd127SDag-Erling Smørgrav debug("getpeername: %.100s", strerror(errno)); 7701ec0d754SDag-Erling Smørgrav cleanup_exit(255); 771989dd127SDag-Erling Smørgrav } 772989dd127SDag-Erling Smørgrav } 773989dd127SDag-Erling Smørgrav 774989dd127SDag-Erling Smørgrav record_utmp_only(pid, s->tty, s->pw->pw_name, 775cf2b5f3bSDag-Erling Smørgrav get_remote_name_or_ip(utmp_len, options.use_dns), 7767ac32603SHajimu UMEMOTO (struct sockaddr *)&from, fromlen); 777989dd127SDag-Erling Smørgrav } 778989dd127SDag-Erling Smørgrav #endif 779989dd127SDag-Erling Smørgrav 780af12a3e7SDag-Erling Smørgrav /* 781af12a3e7SDag-Erling Smørgrav * This is called to fork and execute a command. If another command is 782af12a3e7SDag-Erling Smørgrav * to be forced, execute that instead. 783af12a3e7SDag-Erling Smørgrav */ 784d4af9e69SDag-Erling Smørgrav int 785af12a3e7SDag-Erling Smørgrav do_exec(Session *s, const char *command) 786af12a3e7SDag-Erling Smørgrav { 787d4af9e69SDag-Erling Smørgrav int ret; 788d4af9e69SDag-Erling Smørgrav 789333ee039SDag-Erling Smørgrav if (options.adm_forced_command) { 790333ee039SDag-Erling Smørgrav original_command = command; 791333ee039SDag-Erling Smørgrav command = options.adm_forced_command; 792b15c8340SDag-Erling Smørgrav if (IS_INTERNAL_SFTP(command)) { 793b15c8340SDag-Erling Smørgrav s->is_subsystem = s->is_subsystem ? 794b15c8340SDag-Erling Smørgrav SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR; 795b15c8340SDag-Erling Smørgrav } else if (s->is_subsystem) 796d4af9e69SDag-Erling Smørgrav s->is_subsystem = SUBSYSTEM_EXT; 797333ee039SDag-Erling Smørgrav debug("Forced command (config) '%.900s'", command); 798333ee039SDag-Erling Smørgrav } else if (forced_command) { 799af12a3e7SDag-Erling Smørgrav original_command = command; 800af12a3e7SDag-Erling Smørgrav command = forced_command; 801b15c8340SDag-Erling Smørgrav if (IS_INTERNAL_SFTP(command)) { 802b15c8340SDag-Erling Smørgrav s->is_subsystem = s->is_subsystem ? 803b15c8340SDag-Erling Smørgrav SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR; 804b15c8340SDag-Erling Smørgrav } else if (s->is_subsystem) 805d4af9e69SDag-Erling Smørgrav s->is_subsystem = SUBSYSTEM_EXT; 806333ee039SDag-Erling Smørgrav debug("Forced command (key option) '%.900s'", command); 807af12a3e7SDag-Erling Smørgrav } 808af12a3e7SDag-Erling Smørgrav 809aa49c926SDag-Erling Smørgrav #ifdef SSH_AUDIT_EVENTS 810aa49c926SDag-Erling Smørgrav if (command != NULL) 811aa49c926SDag-Erling Smørgrav PRIVSEP(audit_run_command(command)); 812aa49c926SDag-Erling Smørgrav else if (s->ttyfd == -1) { 813aa49c926SDag-Erling Smørgrav char *shell = s->pw->pw_shell; 814aa49c926SDag-Erling Smørgrav 815aa49c926SDag-Erling Smørgrav if (shell[0] == '\0') /* empty shell means /bin/sh */ 816aa49c926SDag-Erling Smørgrav shell =_PATH_BSHELL; 817aa49c926SDag-Erling Smørgrav PRIVSEP(audit_run_command(shell)); 818cf2b5f3bSDag-Erling Smørgrav } 819cf2b5f3bSDag-Erling Smørgrav #endif 820af12a3e7SDag-Erling Smørgrav if (s->ttyfd != -1) 821d4af9e69SDag-Erling Smørgrav ret = do_exec_pty(s, command); 822af12a3e7SDag-Erling Smørgrav else 823d4af9e69SDag-Erling Smørgrav ret = do_exec_no_pty(s, command); 824af12a3e7SDag-Erling Smørgrav 825af12a3e7SDag-Erling Smørgrav original_command = NULL; 826af12a3e7SDag-Erling Smørgrav 82721e764dfSDag-Erling Smørgrav /* 82821e764dfSDag-Erling Smørgrav * Clear loginmsg: it's the child's responsibility to display 82921e764dfSDag-Erling Smørgrav * it to the user, otherwise multiple sessions may accumulate 83021e764dfSDag-Erling Smørgrav * multiple copies of the login messages. 83121e764dfSDag-Erling Smørgrav */ 83221e764dfSDag-Erling Smørgrav buffer_clear(&loginmsg); 833d4af9e69SDag-Erling Smørgrav 834d4af9e69SDag-Erling Smørgrav return ret; 83521e764dfSDag-Erling Smørgrav } 836af12a3e7SDag-Erling Smørgrav 837c2d3a559SKris Kennaway /* administrative, login(1)-like work */ 838ca3176e7SBrian Feldman void 839c2d3a559SKris Kennaway do_login(Session *s, const char *command) 840c2d3a559SKris Kennaway { 841c2d3a559SKris Kennaway socklen_t fromlen; 842c2d3a559SKris Kennaway struct sockaddr_storage from; 843c2d3a559SKris Kennaway struct passwd * pw = s->pw; 844c2d3a559SKris Kennaway pid_t pid = getpid(); 845c2d3a559SKris Kennaway 846c2d3a559SKris Kennaway /* 847c2d3a559SKris Kennaway * Get IP address of client. If the connection is not a socket, let 848c2d3a559SKris Kennaway * the address be 0.0.0.0. 849c2d3a559SKris Kennaway */ 850c2d3a559SKris Kennaway memset(&from, 0, sizeof(from)); 851c2d3a559SKris Kennaway fromlen = sizeof(from); 8527ac32603SHajimu UMEMOTO if (packet_connection_is_on_socket()) { 853c2d3a559SKris Kennaway if (getpeername(packet_get_connection_in(), 854c2d3a559SKris Kennaway (struct sockaddr *)&from, &fromlen) < 0) { 855c2d3a559SKris Kennaway debug("getpeername: %.100s", strerror(errno)); 8561ec0d754SDag-Erling Smørgrav cleanup_exit(255); 857c2d3a559SKris Kennaway } 858c2d3a559SKris Kennaway } 859c2d3a559SKris Kennaway 86080628bacSDag-Erling Smørgrav /* Record that there was a login on that tty from the remote host. */ 86180628bacSDag-Erling Smørgrav if (!use_privsep) 86280628bacSDag-Erling Smørgrav record_login(pid, s->tty, pw->pw_name, pw->pw_uid, 86380628bacSDag-Erling Smørgrav get_remote_name_or_ip(utmp_len, 864cf2b5f3bSDag-Erling Smørgrav options.use_dns), 8657ac32603SHajimu UMEMOTO (struct sockaddr *)&from, fromlen); 86680628bacSDag-Erling Smørgrav 867098de0c1SAndrey A. Chernov #ifdef USE_PAM 868c2d3a559SKris Kennaway /* 869989dd127SDag-Erling Smørgrav * If password change is needed, do it now. 870989dd127SDag-Erling Smørgrav * This needs to occur before the ~/.hushlogin check. 871c2d3a559SKris Kennaway */ 8721ec0d754SDag-Erling Smørgrav if (options.use_pam && !use_privsep && s->authctxt->force_pwchange) { 8731ec0d754SDag-Erling Smørgrav display_loginmsg(); 874989dd127SDag-Erling Smørgrav do_pam_chauthtok(); 8751ec0d754SDag-Erling Smørgrav s->authctxt->force_pwchange = 0; 876cf2b5f3bSDag-Erling Smørgrav /* XXX - signal [net] parent to enable forwardings */ 877989dd127SDag-Erling Smørgrav } 878989dd127SDag-Erling Smørgrav #endif 879af12a3e7SDag-Erling Smørgrav 880989dd127SDag-Erling Smørgrav if (check_quietlogin(s, command)) 881989dd127SDag-Erling Smørgrav return; 882989dd127SDag-Erling Smørgrav 8831ec0d754SDag-Erling Smørgrav display_loginmsg(); 884f388f5efSDag-Erling Smørgrav 885ca3176e7SBrian Feldman do_motd(); 886ca3176e7SBrian Feldman } 887ca3176e7SBrian Feldman 888ca3176e7SBrian Feldman /* 889ca3176e7SBrian Feldman * Display the message of the day. 890ca3176e7SBrian Feldman */ 891ca3176e7SBrian Feldman void 892ca3176e7SBrian Feldman do_motd(void) 893ca3176e7SBrian Feldman { 894ca3176e7SBrian Feldman FILE *f; 895ca3176e7SBrian Feldman char buf[256]; 89659ac432aSAndrey A. Chernov #ifdef HAVE_LOGIN_CAP 89759ac432aSAndrey A. Chernov const char *fname; 89859ac432aSAndrey A. Chernov #endif 89959ac432aSAndrey A. Chernov 90059ac432aSAndrey A. Chernov #ifdef HAVE_LOGIN_CAP 90159ac432aSAndrey A. Chernov fname = login_getcapstr(lc, "copyright", NULL, NULL); 90259ac432aSAndrey A. Chernov if (fname != NULL && (f = fopen(fname, "r")) != NULL) { 90359ac432aSAndrey A. Chernov while (fgets(buf, sizeof(buf), f) != NULL) 90459ac432aSAndrey A. Chernov fputs(buf, stdout); 90559ac432aSAndrey A. Chernov fclose(f); 90659ac432aSAndrey A. Chernov } else 90759ac432aSAndrey A. Chernov #endif /* HAVE_LOGIN_CAP */ 90859ac432aSAndrey A. Chernov (void)printf("%s\n\t%s %s\n", 90959ac432aSAndrey A. Chernov "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994", 91059ac432aSAndrey A. Chernov "The Regents of the University of California. ", 91159ac432aSAndrey A. Chernov "All rights reserved."); 91259ac432aSAndrey A. Chernov 91359ac432aSAndrey A. Chernov (void)printf("\n"); 914ca3176e7SBrian Feldman 915ca3176e7SBrian Feldman if (options.print_motd) { 916c2d3a559SKris Kennaway #ifdef HAVE_LOGIN_CAP 917c2d3a559SKris Kennaway f = fopen(login_getcapstr(lc, "welcome", "/etc/motd", 918c2d3a559SKris Kennaway "/etc/motd"), "r"); 919af12a3e7SDag-Erling Smørgrav #else 920c2d3a559SKris Kennaway f = fopen("/etc/motd", "r"); 921af12a3e7SDag-Erling Smørgrav #endif 922c2d3a559SKris Kennaway if (f) { 923c2d3a559SKris Kennaway while (fgets(buf, sizeof(buf), f)) 924c2d3a559SKris Kennaway fputs(buf, stdout); 925c2d3a559SKris Kennaway fclose(f); 926c2d3a559SKris Kennaway } 927c2d3a559SKris Kennaway } 928ca3176e7SBrian Feldman } 929c2d3a559SKris Kennaway 930af12a3e7SDag-Erling Smørgrav 931ca3176e7SBrian Feldman /* 932ca3176e7SBrian Feldman * Check for quiet login, either .hushlogin or command given. 933ca3176e7SBrian Feldman */ 934ca3176e7SBrian Feldman int 935ca3176e7SBrian Feldman check_quietlogin(Session *s, const char *command) 936ca3176e7SBrian Feldman { 937ca3176e7SBrian Feldman char buf[256]; 938ca3176e7SBrian Feldman struct passwd *pw = s->pw; 939ca3176e7SBrian Feldman struct stat st; 940ca3176e7SBrian Feldman 941ca3176e7SBrian Feldman /* Return 1 if .hushlogin exists or a command given. */ 942ca3176e7SBrian Feldman if (command != NULL) 943ca3176e7SBrian Feldman return 1; 944ca3176e7SBrian Feldman snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir); 945c2d3a559SKris Kennaway #ifdef HAVE_LOGIN_CAP 946ca3176e7SBrian Feldman if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0) 947ca3176e7SBrian Feldman return 1; 948ca3176e7SBrian Feldman #else 949ca3176e7SBrian Feldman if (stat(buf, &st) >= 0) 950ca3176e7SBrian Feldman return 1; 951ca3176e7SBrian Feldman #endif 952ca3176e7SBrian Feldman return 0; 953c2d3a559SKris Kennaway } 954c2d3a559SKris Kennaway 955a04a10f8SKris Kennaway /* 956a04a10f8SKris Kennaway * Sets the value of the given variable in the environment. If the variable 957cce7d346SDag-Erling Smørgrav * already exists, its value is overridden. 958a04a10f8SKris Kennaway */ 959cf2b5f3bSDag-Erling Smørgrav void 960ca3176e7SBrian Feldman child_set_env(char ***envp, u_int *envsizep, const char *name, 961a04a10f8SKris Kennaway const char *value) 962a04a10f8SKris Kennaway { 963a04a10f8SKris Kennaway char **env; 964b69cd7f2SJacques Vidrine u_int envsize; 965b69cd7f2SJacques Vidrine u_int i, namelen; 966a04a10f8SKris Kennaway 967a04a10f8SKris Kennaway /* 968cf2b5f3bSDag-Erling Smørgrav * If we're passed an uninitialized list, allocate a single null 969cf2b5f3bSDag-Erling Smørgrav * entry before continuing. 970cf2b5f3bSDag-Erling Smørgrav */ 971cf2b5f3bSDag-Erling Smørgrav if (*envp == NULL && *envsizep == 0) { 972cf2b5f3bSDag-Erling Smørgrav *envp = xmalloc(sizeof(char *)); 973cf2b5f3bSDag-Erling Smørgrav *envp[0] = NULL; 974cf2b5f3bSDag-Erling Smørgrav *envsizep = 1; 975cf2b5f3bSDag-Erling Smørgrav } 976cf2b5f3bSDag-Erling Smørgrav 977cf2b5f3bSDag-Erling Smørgrav /* 978a04a10f8SKris Kennaway * Find the slot where the value should be stored. If the variable 979a04a10f8SKris Kennaway * already exists, we reuse the slot; otherwise we append a new slot 980a04a10f8SKris Kennaway * at the end of the array, expanding if necessary. 981a04a10f8SKris Kennaway */ 982a04a10f8SKris Kennaway env = *envp; 983a04a10f8SKris Kennaway namelen = strlen(name); 984a04a10f8SKris Kennaway for (i = 0; env[i]; i++) 985a04a10f8SKris Kennaway if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=') 986a04a10f8SKris Kennaway break; 987a04a10f8SKris Kennaway if (env[i]) { 988a04a10f8SKris Kennaway /* Reuse the slot. */ 989a04a10f8SKris Kennaway xfree(env[i]); 990a04a10f8SKris Kennaway } else { 991a04a10f8SKris Kennaway /* New variable. Expand if necessary. */ 992b69cd7f2SJacques Vidrine envsize = *envsizep; 993b69cd7f2SJacques Vidrine if (i >= envsize - 1) { 994b69cd7f2SJacques Vidrine if (envsize >= 1000) 995b69cd7f2SJacques Vidrine fatal("child_set_env: too many env vars"); 996b69cd7f2SJacques Vidrine envsize += 50; 997333ee039SDag-Erling Smørgrav env = (*envp) = xrealloc(env, envsize, sizeof(char *)); 998b69cd7f2SJacques Vidrine *envsizep = envsize; 999a04a10f8SKris Kennaway } 1000a04a10f8SKris Kennaway /* Need to set the NULL pointer at end of array beyond the new slot. */ 1001a04a10f8SKris Kennaway env[i + 1] = NULL; 1002a04a10f8SKris Kennaway } 1003a04a10f8SKris Kennaway 1004a04a10f8SKris Kennaway /* Allocate space and format the variable in the appropriate slot. */ 1005a04a10f8SKris Kennaway env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1); 1006a04a10f8SKris Kennaway snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value); 1007a04a10f8SKris Kennaway } 1008a04a10f8SKris Kennaway 1009a04a10f8SKris Kennaway /* 1010a04a10f8SKris Kennaway * Reads environment variables from the given file and adds/overrides them 1011a04a10f8SKris Kennaway * into the environment. If the file does not exist, this does nothing. 1012a04a10f8SKris Kennaway * Otherwise, it must consist of empty lines, comments (line starts with '#') 1013a04a10f8SKris Kennaway * and assignments of the form name=value. No other forms are allowed. 1014a04a10f8SKris Kennaway */ 1015af12a3e7SDag-Erling Smørgrav static void 1016ca3176e7SBrian Feldman read_environment_file(char ***env, u_int *envsize, 1017a04a10f8SKris Kennaway const char *filename) 1018a04a10f8SKris Kennaway { 1019a04a10f8SKris Kennaway FILE *f; 1020a04a10f8SKris Kennaway char buf[4096]; 1021a04a10f8SKris Kennaway char *cp, *value; 1022a82e551fSDag-Erling Smørgrav u_int lineno = 0; 1023a04a10f8SKris Kennaway 1024a04a10f8SKris Kennaway f = fopen(filename, "r"); 1025a04a10f8SKris Kennaway if (!f) 1026a04a10f8SKris Kennaway return; 1027a04a10f8SKris Kennaway 1028a04a10f8SKris Kennaway while (fgets(buf, sizeof(buf), f)) { 1029a82e551fSDag-Erling Smørgrav if (++lineno > 1000) 1030a82e551fSDag-Erling Smørgrav fatal("Too many lines in environment file %s", filename); 1031a04a10f8SKris Kennaway for (cp = buf; *cp == ' ' || *cp == '\t'; cp++) 1032a04a10f8SKris Kennaway ; 1033a04a10f8SKris Kennaway if (!*cp || *cp == '#' || *cp == '\n') 1034a04a10f8SKris Kennaway continue; 1035d4af9e69SDag-Erling Smørgrav 1036d4af9e69SDag-Erling Smørgrav cp[strcspn(cp, "\n")] = '\0'; 1037d4af9e69SDag-Erling Smørgrav 1038a04a10f8SKris Kennaway value = strchr(cp, '='); 1039a04a10f8SKris Kennaway if (value == NULL) { 1040a82e551fSDag-Erling Smørgrav fprintf(stderr, "Bad line %u in %.100s\n", lineno, 1041a82e551fSDag-Erling Smørgrav filename); 1042a04a10f8SKris Kennaway continue; 1043a04a10f8SKris Kennaway } 1044db1cb46cSKris Kennaway /* 1045db1cb46cSKris Kennaway * Replace the equals sign by nul, and advance value to 1046db1cb46cSKris Kennaway * the value string. 1047db1cb46cSKris Kennaway */ 1048a04a10f8SKris Kennaway *value = '\0'; 1049a04a10f8SKris Kennaway value++; 1050a04a10f8SKris Kennaway child_set_env(env, envsize, cp, value); 1051a04a10f8SKris Kennaway } 1052a04a10f8SKris Kennaway fclose(f); 1053a04a10f8SKris Kennaway } 1054a04a10f8SKris Kennaway 1055cf2b5f3bSDag-Erling Smørgrav #ifdef HAVE_ETC_DEFAULT_LOGIN 1056cf2b5f3bSDag-Erling Smørgrav /* 1057cf2b5f3bSDag-Erling Smørgrav * Return named variable from specified environment, or NULL if not present. 1058cf2b5f3bSDag-Erling Smørgrav */ 1059cf2b5f3bSDag-Erling Smørgrav static char * 1060cf2b5f3bSDag-Erling Smørgrav child_get_env(char **env, const char *name) 1061cf2b5f3bSDag-Erling Smørgrav { 1062cf2b5f3bSDag-Erling Smørgrav int i; 1063cf2b5f3bSDag-Erling Smørgrav size_t len; 1064cf2b5f3bSDag-Erling Smørgrav 1065cf2b5f3bSDag-Erling Smørgrav len = strlen(name); 1066cf2b5f3bSDag-Erling Smørgrav for (i=0; env[i] != NULL; i++) 1067cf2b5f3bSDag-Erling Smørgrav if (strncmp(name, env[i], len) == 0 && env[i][len] == '=') 1068cf2b5f3bSDag-Erling Smørgrav return(env[i] + len + 1); 1069cf2b5f3bSDag-Erling Smørgrav return NULL; 1070cf2b5f3bSDag-Erling Smørgrav } 1071cf2b5f3bSDag-Erling Smørgrav 1072cf2b5f3bSDag-Erling Smørgrav /* 1073cf2b5f3bSDag-Erling Smørgrav * Read /etc/default/login. 1074cf2b5f3bSDag-Erling Smørgrav * We pick up the PATH (or SUPATH for root) and UMASK. 1075cf2b5f3bSDag-Erling Smørgrav */ 1076cf2b5f3bSDag-Erling Smørgrav static void 1077cf2b5f3bSDag-Erling Smørgrav read_etc_default_login(char ***env, u_int *envsize, uid_t uid) 1078cf2b5f3bSDag-Erling Smørgrav { 1079cf2b5f3bSDag-Erling Smørgrav char **tmpenv = NULL, *var; 1080cf2b5f3bSDag-Erling Smørgrav u_int i, tmpenvsize = 0; 10811ec0d754SDag-Erling Smørgrav u_long mask; 1082cf2b5f3bSDag-Erling Smørgrav 1083cf2b5f3bSDag-Erling Smørgrav /* 1084cf2b5f3bSDag-Erling Smørgrav * We don't want to copy the whole file to the child's environment, 1085cf2b5f3bSDag-Erling Smørgrav * so we use a temporary environment and copy the variables we're 1086cf2b5f3bSDag-Erling Smørgrav * interested in. 1087cf2b5f3bSDag-Erling Smørgrav */ 1088cf2b5f3bSDag-Erling Smørgrav read_environment_file(&tmpenv, &tmpenvsize, "/etc/default/login"); 1089cf2b5f3bSDag-Erling Smørgrav 1090cf2b5f3bSDag-Erling Smørgrav if (tmpenv == NULL) 1091cf2b5f3bSDag-Erling Smørgrav return; 1092cf2b5f3bSDag-Erling Smørgrav 1093cf2b5f3bSDag-Erling Smørgrav if (uid == 0) 1094cf2b5f3bSDag-Erling Smørgrav var = child_get_env(tmpenv, "SUPATH"); 1095cf2b5f3bSDag-Erling Smørgrav else 1096cf2b5f3bSDag-Erling Smørgrav var = child_get_env(tmpenv, "PATH"); 1097cf2b5f3bSDag-Erling Smørgrav if (var != NULL) 1098cf2b5f3bSDag-Erling Smørgrav child_set_env(env, envsize, "PATH", var); 1099cf2b5f3bSDag-Erling Smørgrav 1100cf2b5f3bSDag-Erling Smørgrav if ((var = child_get_env(tmpenv, "UMASK")) != NULL) 1101cf2b5f3bSDag-Erling Smørgrav if (sscanf(var, "%5lo", &mask) == 1) 11021ec0d754SDag-Erling Smørgrav umask((mode_t)mask); 1103cf2b5f3bSDag-Erling Smørgrav 1104cf2b5f3bSDag-Erling Smørgrav for (i = 0; tmpenv[i] != NULL; i++) 1105cf2b5f3bSDag-Erling Smørgrav xfree(tmpenv[i]); 1106cf2b5f3bSDag-Erling Smørgrav xfree(tmpenv); 1107cf2b5f3bSDag-Erling Smørgrav } 1108cf2b5f3bSDag-Erling Smørgrav #endif /* HAVE_ETC_DEFAULT_LOGIN */ 1109cf2b5f3bSDag-Erling Smørgrav 1110d4ecd108SDag-Erling Smørgrav void 1111d4ecd108SDag-Erling Smørgrav copy_environment(char **source, char ***env, u_int *envsize) 111209958426SBrian Feldman { 1113989dd127SDag-Erling Smørgrav char *var_name, *var_val; 111409958426SBrian Feldman int i; 111509958426SBrian Feldman 1116989dd127SDag-Erling Smørgrav if (source == NULL) 111709958426SBrian Feldman return; 111809958426SBrian Feldman 1119989dd127SDag-Erling Smørgrav for(i = 0; source[i] != NULL; i++) { 1120989dd127SDag-Erling Smørgrav var_name = xstrdup(source[i]); 1121989dd127SDag-Erling Smørgrav if ((var_val = strstr(var_name, "=")) == NULL) { 1122989dd127SDag-Erling Smørgrav xfree(var_name); 112309958426SBrian Feldman continue; 1124989dd127SDag-Erling Smørgrav } 1125989dd127SDag-Erling Smørgrav *var_val++ = '\0'; 112609958426SBrian Feldman 1127989dd127SDag-Erling Smørgrav debug3("Copy environment: %s=%s", var_name, var_val); 112809958426SBrian Feldman child_set_env(env, envsize, var_name, var_val); 1129989dd127SDag-Erling Smørgrav 1130989dd127SDag-Erling Smørgrav xfree(var_name); 113109958426SBrian Feldman } 113209958426SBrian Feldman } 113309958426SBrian Feldman 1134af12a3e7SDag-Erling Smørgrav static char ** 1135989dd127SDag-Erling Smørgrav do_setup_env(Session *s, const char *shell) 1136a04a10f8SKris Kennaway { 1137a04a10f8SKris Kennaway char buf[256]; 1138af12a3e7SDag-Erling Smørgrav u_int i, envsize; 1139333ee039SDag-Erling Smørgrav char **env, *laddr; 1140333ee039SDag-Erling Smørgrav struct passwd *pw = s->pw; 11417aee6ffeSDag-Erling Smørgrav #if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN) 1142333ee039SDag-Erling Smørgrav char *path = NULL; 1143333ee039SDag-Erling Smørgrav #else 1144c62005fcSDag-Erling Smørgrav extern char **environ; 1145c62005fcSDag-Erling Smørgrav char **senv, **var; 1146c62005fcSDag-Erling Smørgrav #endif 1147a04a10f8SKris Kennaway 1148a04a10f8SKris Kennaway /* Initialize the environment. */ 1149a04a10f8SKris Kennaway envsize = 100; 1150333ee039SDag-Erling Smørgrav env = xcalloc(envsize, sizeof(char *)); 1151a04a10f8SKris Kennaway env[0] = NULL; 1152989dd127SDag-Erling Smørgrav 1153989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN 1154989dd127SDag-Erling Smørgrav /* 1155989dd127SDag-Erling Smørgrav * The Windows environment contains some setting which are 1156989dd127SDag-Erling Smørgrav * important for a running system. They must not be dropped. 1157989dd127SDag-Erling Smørgrav */ 1158aa49c926SDag-Erling Smørgrav { 1159aa49c926SDag-Erling Smørgrav char **p; 1160aa49c926SDag-Erling Smørgrav 1161aa49c926SDag-Erling Smørgrav p = fetch_windows_environment(); 1162aa49c926SDag-Erling Smørgrav copy_environment(p, &env, &envsize); 1163aa49c926SDag-Erling Smørgrav free_windows_environment(p); 1164aa49c926SDag-Erling Smørgrav } 1165989dd127SDag-Erling Smørgrav #endif 1166a04a10f8SKris Kennaway 1167c62005fcSDag-Erling Smørgrav if (getenv("TZ")) 1168c62005fcSDag-Erling Smørgrav child_set_env(&env, &envsize, "TZ", getenv("TZ")); 1169cf2b5f3bSDag-Erling Smørgrav 1170cf2b5f3bSDag-Erling Smørgrav #ifdef GSSAPI 1171cf2b5f3bSDag-Erling Smørgrav /* Allow any GSSAPI methods that we've used to alter 1172cf2b5f3bSDag-Erling Smørgrav * the childs environment as they see fit 1173cf2b5f3bSDag-Erling Smørgrav */ 1174cf2b5f3bSDag-Erling Smørgrav ssh_gssapi_do_child(&env, &envsize); 1175cf2b5f3bSDag-Erling Smørgrav #endif 1176cf2b5f3bSDag-Erling Smørgrav 1177a04a10f8SKris Kennaway if (!options.use_login) { 1178a04a10f8SKris Kennaway /* Set basic environment. */ 117921e764dfSDag-Erling Smørgrav for (i = 0; i < s->num_env; i++) 118021e764dfSDag-Erling Smørgrav child_set_env(&env, &envsize, s->env[i].name, 118121e764dfSDag-Erling Smørgrav s->env[i].val); 118221e764dfSDag-Erling Smørgrav 1183a04a10f8SKris Kennaway child_set_env(&env, &envsize, "USER", pw->pw_name); 1184a04a10f8SKris Kennaway child_set_env(&env, &envsize, "LOGNAME", pw->pw_name); 1185e73e9afaSDag-Erling Smørgrav #ifdef _AIX 1186e73e9afaSDag-Erling Smørgrav child_set_env(&env, &envsize, "LOGIN", pw->pw_name); 1187e73e9afaSDag-Erling Smørgrav #endif 1188a04a10f8SKris Kennaway child_set_env(&env, &envsize, "HOME", pw->pw_dir); 1189c62005fcSDag-Erling Smørgrav snprintf(buf, sizeof buf, "%.200s/%.50s", 1190c62005fcSDag-Erling Smørgrav _PATH_MAILDIR, pw->pw_name); 1191c62005fcSDag-Erling Smørgrav child_set_env(&env, &envsize, "MAIL", buf); 1192989dd127SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP 1193c62005fcSDag-Erling Smørgrav child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); 1194c62005fcSDag-Erling Smørgrav child_set_env(&env, &envsize, "TERM", "su"); 1195c62005fcSDag-Erling Smørgrav senv = environ; 1196c62005fcSDag-Erling Smørgrav environ = xmalloc(sizeof(char *)); 1197c62005fcSDag-Erling Smørgrav *environ = NULL; 1198c62005fcSDag-Erling Smørgrav (void) setusercontext(lc, pw, pw->pw_uid, 1199c62005fcSDag-Erling Smørgrav LOGIN_SETENV|LOGIN_SETPATH); 1200c62005fcSDag-Erling Smørgrav copy_environment(environ, &env, &envsize); 1201c62005fcSDag-Erling Smørgrav for (var = environ; *var != NULL; ++var) 1202c62005fcSDag-Erling Smørgrav xfree(*var); 1203c62005fcSDag-Erling Smørgrav xfree(environ); 1204c62005fcSDag-Erling Smørgrav environ = senv; 1205989dd127SDag-Erling Smørgrav #else /* HAVE_LOGIN_CAP */ 1206989dd127SDag-Erling Smørgrav # ifndef HAVE_CYGWIN 1207989dd127SDag-Erling Smørgrav /* 1208989dd127SDag-Erling Smørgrav * There's no standard path on Windows. The path contains 1209989dd127SDag-Erling Smørgrav * important components pointing to the system directories, 1210989dd127SDag-Erling Smørgrav * needed for loading shared libraries. So the path better 1211989dd127SDag-Erling Smørgrav * remains intact here. 1212989dd127SDag-Erling Smørgrav */ 1213cf2b5f3bSDag-Erling Smørgrav # ifdef HAVE_ETC_DEFAULT_LOGIN 1214cf2b5f3bSDag-Erling Smørgrav read_etc_default_login(&env, &envsize, pw->pw_uid); 1215cf2b5f3bSDag-Erling Smørgrav path = child_get_env(env, "PATH"); 1216cf2b5f3bSDag-Erling Smørgrav # endif /* HAVE_ETC_DEFAULT_LOGIN */ 1217cf2b5f3bSDag-Erling Smørgrav if (path == NULL || *path == '\0') { 1218989dd127SDag-Erling Smørgrav child_set_env(&env, &envsize, "PATH", 1219cf2b5f3bSDag-Erling Smørgrav s->pw->pw_uid == 0 ? 1220cf2b5f3bSDag-Erling Smørgrav SUPERUSER_PATH : _PATH_STDPATH); 1221cf2b5f3bSDag-Erling Smørgrav } 1222989dd127SDag-Erling Smørgrav # endif /* HAVE_CYGWIN */ 1223989dd127SDag-Erling Smørgrav #endif /* HAVE_LOGIN_CAP */ 1224a04a10f8SKris Kennaway 1225a04a10f8SKris Kennaway /* Normal systems set SHELL by default. */ 1226a04a10f8SKris Kennaway child_set_env(&env, &envsize, "SHELL", shell); 1227a04a10f8SKris Kennaway } 1228a04a10f8SKris Kennaway 1229a04a10f8SKris Kennaway /* Set custom environment options from RSA authentication. */ 12301c5093bbSJacques Vidrine if (!options.use_login) { 1231a04a10f8SKris Kennaway while (custom_environment) { 1232a04a10f8SKris Kennaway struct envstring *ce = custom_environment; 1233f388f5efSDag-Erling Smørgrav char *str = ce->s; 1234af12a3e7SDag-Erling Smørgrav 1235f388f5efSDag-Erling Smørgrav for (i = 0; str[i] != '=' && str[i]; i++) 1236af12a3e7SDag-Erling Smørgrav ; 1237f388f5efSDag-Erling Smørgrav if (str[i] == '=') { 1238f388f5efSDag-Erling Smørgrav str[i] = 0; 1239f388f5efSDag-Erling Smørgrav child_set_env(&env, &envsize, str, str + i + 1); 1240a04a10f8SKris Kennaway } 1241a04a10f8SKris Kennaway custom_environment = ce->next; 1242a04a10f8SKris Kennaway xfree(ce->s); 1243a04a10f8SKris Kennaway xfree(ce); 1244a04a10f8SKris Kennaway } 12451c5093bbSJacques Vidrine } 1246a04a10f8SKris Kennaway 1247f388f5efSDag-Erling Smørgrav /* SSH_CLIENT deprecated */ 1248a04a10f8SKris Kennaway snprintf(buf, sizeof buf, "%.50s %d %d", 1249a04a10f8SKris Kennaway get_remote_ipaddr(), get_remote_port(), get_local_port()); 1250a04a10f8SKris Kennaway child_set_env(&env, &envsize, "SSH_CLIENT", buf); 1251a04a10f8SKris Kennaway 1252e73e9afaSDag-Erling Smørgrav laddr = get_local_ipaddr(packet_get_connection_in()); 1253f388f5efSDag-Erling Smørgrav snprintf(buf, sizeof buf, "%.50s %d %.50s %d", 1254e73e9afaSDag-Erling Smørgrav get_remote_ipaddr(), get_remote_port(), laddr, get_local_port()); 1255e73e9afaSDag-Erling Smørgrav xfree(laddr); 1256f388f5efSDag-Erling Smørgrav child_set_env(&env, &envsize, "SSH_CONNECTION", buf); 1257f388f5efSDag-Erling Smørgrav 1258ca3176e7SBrian Feldman if (s->ttyfd != -1) 1259ca3176e7SBrian Feldman child_set_env(&env, &envsize, "SSH_TTY", s->tty); 1260ca3176e7SBrian Feldman if (s->term) 1261ca3176e7SBrian Feldman child_set_env(&env, &envsize, "TERM", s->term); 1262ca3176e7SBrian Feldman if (s->display) 1263ca3176e7SBrian Feldman child_set_env(&env, &envsize, "DISPLAY", s->display); 1264c2d3a559SKris Kennaway if (original_command) 1265c2d3a559SKris Kennaway child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND", 1266c2d3a559SKris Kennaway original_command); 1267989dd127SDag-Erling Smørgrav 1268f388f5efSDag-Erling Smørgrav #ifdef _UNICOS 1269f388f5efSDag-Erling Smørgrav if (cray_tmpdir[0] != '\0') 1270f388f5efSDag-Erling Smørgrav child_set_env(&env, &envsize, "TMPDIR", cray_tmpdir); 1271f388f5efSDag-Erling Smørgrav #endif /* _UNICOS */ 1272f388f5efSDag-Erling Smørgrav 1273aa49c926SDag-Erling Smørgrav /* 1274aa49c926SDag-Erling Smørgrav * Since we clear KRB5CCNAME at startup, if it's set now then it 1275aa49c926SDag-Erling Smørgrav * must have been set by a native authentication method (eg AIX or 1276aa49c926SDag-Erling Smørgrav * SIA), so copy it to the child. 1277aa49c926SDag-Erling Smørgrav */ 1278aa49c926SDag-Erling Smørgrav { 1279aa49c926SDag-Erling Smørgrav char *cp; 1280aa49c926SDag-Erling Smørgrav 1281aa49c926SDag-Erling Smørgrav if ((cp = getenv("KRB5CCNAME")) != NULL) 1282aa49c926SDag-Erling Smørgrav child_set_env(&env, &envsize, "KRB5CCNAME", cp); 1283aa49c926SDag-Erling Smørgrav } 1284aa49c926SDag-Erling Smørgrav 1285989dd127SDag-Erling Smørgrav #ifdef _AIX 1286989dd127SDag-Erling Smørgrav { 1287989dd127SDag-Erling Smørgrav char *cp; 1288989dd127SDag-Erling Smørgrav 1289989dd127SDag-Erling Smørgrav if ((cp = getenv("AUTHSTATE")) != NULL) 1290989dd127SDag-Erling Smørgrav child_set_env(&env, &envsize, "AUTHSTATE", cp); 1291989dd127SDag-Erling Smørgrav read_environment_file(&env, &envsize, "/etc/environment"); 1292989dd127SDag-Erling Smørgrav } 1293989dd127SDag-Erling Smørgrav #endif 1294e8aafc91SKris Kennaway #ifdef KRB5 12955962c0e9SDag-Erling Smørgrav if (s->authctxt->krb5_ccname) 1296af12a3e7SDag-Erling Smørgrav child_set_env(&env, &envsize, "KRB5CCNAME", 12975962c0e9SDag-Erling Smørgrav s->authctxt->krb5_ccname); 1298af12a3e7SDag-Erling Smørgrav #endif 129909958426SBrian Feldman #ifdef USE_PAM 1300f388f5efSDag-Erling Smørgrav /* 1301f388f5efSDag-Erling Smørgrav * Pull in any environment variables that may have 1302f388f5efSDag-Erling Smørgrav * been set by PAM. 1303f388f5efSDag-Erling Smørgrav */ 1304cf2b5f3bSDag-Erling Smørgrav if (options.use_pam) { 13051ec0d754SDag-Erling Smørgrav char **p; 1306f388f5efSDag-Erling Smørgrav 13071ec0d754SDag-Erling Smørgrav p = fetch_pam_child_environment(); 13081ec0d754SDag-Erling Smørgrav copy_environment(p, &env, &envsize); 13091ec0d754SDag-Erling Smørgrav free_pam_environment(p); 13101ec0d754SDag-Erling Smørgrav 13111ec0d754SDag-Erling Smørgrav p = fetch_pam_environment(); 1312f388f5efSDag-Erling Smørgrav copy_environment(p, &env, &envsize); 1313f388f5efSDag-Erling Smørgrav free_pam_environment(p); 1314f388f5efSDag-Erling Smørgrav } 131509958426SBrian Feldman #endif /* USE_PAM */ 131609958426SBrian Feldman 131780628bacSDag-Erling Smørgrav if (auth_sock_name != NULL) 1318a04a10f8SKris Kennaway child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, 131980628bacSDag-Erling Smørgrav auth_sock_name); 1320a04a10f8SKris Kennaway 1321a04a10f8SKris Kennaway /* read $HOME/.ssh/environment. */ 1322f388f5efSDag-Erling Smørgrav if (options.permit_user_env && !options.use_login) { 1323db1cb46cSKris Kennaway snprintf(buf, sizeof buf, "%.200s/.ssh/environment", 1324f388f5efSDag-Erling Smørgrav strcmp(pw->pw_dir, "/") ? pw->pw_dir : ""); 1325a04a10f8SKris Kennaway read_environment_file(&env, &envsize, buf); 1326a04a10f8SKris Kennaway } 1327a04a10f8SKris Kennaway if (debug_flag) { 1328a04a10f8SKris Kennaway /* dump the environment */ 1329a04a10f8SKris Kennaway fprintf(stderr, "Environment:\n"); 1330a04a10f8SKris Kennaway for (i = 0; env[i]; i++) 1331a04a10f8SKris Kennaway fprintf(stderr, " %.200s\n", env[i]); 1332a04a10f8SKris Kennaway } 1333af12a3e7SDag-Erling Smørgrav return env; 1334e8aafc91SKris Kennaway } 1335ca3176e7SBrian Feldman 1336ca3176e7SBrian Feldman /* 1337af12a3e7SDag-Erling Smørgrav * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found 1338af12a3e7SDag-Erling Smørgrav * first in this order). 1339ca3176e7SBrian Feldman */ 1340af12a3e7SDag-Erling Smørgrav static void 1341af12a3e7SDag-Erling Smørgrav do_rc_files(Session *s, const char *shell) 1342af12a3e7SDag-Erling Smørgrav { 1343af12a3e7SDag-Erling Smørgrav FILE *f = NULL; 1344af12a3e7SDag-Erling Smørgrav char cmd[1024]; 1345af12a3e7SDag-Erling Smørgrav int do_xauth; 1346af12a3e7SDag-Erling Smørgrav struct stat st; 1347a04a10f8SKris Kennaway 1348af12a3e7SDag-Erling Smørgrav do_xauth = 1349af12a3e7SDag-Erling Smørgrav s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL; 1350a04a10f8SKris Kennaway 1351d4af9e69SDag-Erling Smørgrav /* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */ 1352d4af9e69SDag-Erling Smørgrav if (!s->is_subsystem && options.adm_forced_command == NULL && 1353d4af9e69SDag-Erling Smørgrav !no_user_rc && stat(_PATH_SSH_USER_RC, &st) >= 0) { 1354e9fd63dfSBrian Feldman snprintf(cmd, sizeof cmd, "%s -c '%s %s'", 1355e9fd63dfSBrian Feldman shell, _PATH_BSHELL, _PATH_SSH_USER_RC); 1356a04a10f8SKris Kennaway if (debug_flag) 1357e9fd63dfSBrian Feldman fprintf(stderr, "Running %s\n", cmd); 1358e9fd63dfSBrian Feldman f = popen(cmd, "w"); 1359a04a10f8SKris Kennaway if (f) { 1360ca3176e7SBrian Feldman if (do_xauth) 1361ca3176e7SBrian Feldman fprintf(f, "%s %s\n", s->auth_proto, 1362ca3176e7SBrian Feldman s->auth_data); 1363a04a10f8SKris Kennaway pclose(f); 1364a04a10f8SKris Kennaway } else 1365ca3176e7SBrian Feldman fprintf(stderr, "Could not run %s\n", 1366ca3176e7SBrian Feldman _PATH_SSH_USER_RC); 1367ca3176e7SBrian Feldman } else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) { 1368a04a10f8SKris Kennaway if (debug_flag) 1369ca3176e7SBrian Feldman fprintf(stderr, "Running %s %s\n", _PATH_BSHELL, 1370ca3176e7SBrian Feldman _PATH_SSH_SYSTEM_RC); 1371ca3176e7SBrian Feldman f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w"); 1372a04a10f8SKris Kennaway if (f) { 1373ca3176e7SBrian Feldman if (do_xauth) 1374ca3176e7SBrian Feldman fprintf(f, "%s %s\n", s->auth_proto, 1375ca3176e7SBrian Feldman s->auth_data); 1376a04a10f8SKris Kennaway pclose(f); 1377a04a10f8SKris Kennaway } else 1378ca3176e7SBrian Feldman fprintf(stderr, "Could not run %s\n", 1379ca3176e7SBrian Feldman _PATH_SSH_SYSTEM_RC); 1380ca3176e7SBrian Feldman } else if (do_xauth && options.xauth_location != NULL) { 1381a04a10f8SKris Kennaway /* Add authority data to .Xauthority if appropriate. */ 1382db1cb46cSKris Kennaway if (debug_flag) { 1383db1cb46cSKris Kennaway fprintf(stderr, 1384e73e9afaSDag-Erling Smørgrav "Running %.500s remove %.100s\n", 1385e73e9afaSDag-Erling Smørgrav options.xauth_location, s->auth_display); 1386e73e9afaSDag-Erling Smørgrav fprintf(stderr, 1387e73e9afaSDag-Erling Smørgrav "%.500s add %.100s %.100s %.100s\n", 1388af12a3e7SDag-Erling Smørgrav options.xauth_location, s->auth_display, 1389ca3176e7SBrian Feldman s->auth_proto, s->auth_data); 1390db1cb46cSKris Kennaway } 1391c2d3a559SKris Kennaway snprintf(cmd, sizeof cmd, "%s -q -", 1392c2d3a559SKris Kennaway options.xauth_location); 1393c2d3a559SKris Kennaway f = popen(cmd, "w"); 1394a04a10f8SKris Kennaway if (f) { 1395e73e9afaSDag-Erling Smørgrav fprintf(f, "remove %s\n", 1396e73e9afaSDag-Erling Smørgrav s->auth_display); 1397af12a3e7SDag-Erling Smørgrav fprintf(f, "add %s %s %s\n", 1398af12a3e7SDag-Erling Smørgrav s->auth_display, s->auth_proto, 1399ca3176e7SBrian Feldman s->auth_data); 1400a04a10f8SKris Kennaway pclose(f); 1401c2d3a559SKris Kennaway } else { 1402c2d3a559SKris Kennaway fprintf(stderr, "Could not run %s\n", 1403c2d3a559SKris Kennaway cmd); 1404a04a10f8SKris Kennaway } 1405a04a10f8SKris Kennaway } 1406a04a10f8SKris Kennaway } 1407ca3176e7SBrian Feldman 1408af12a3e7SDag-Erling Smørgrav static void 1409af12a3e7SDag-Erling Smørgrav do_nologin(struct passwd *pw) 1410af12a3e7SDag-Erling Smørgrav { 1411af12a3e7SDag-Erling Smørgrav FILE *f = NULL; 1412b15c8340SDag-Erling Smørgrav char buf[1024], *nl, *def_nl = _PATH_NOLOGIN; 1413b15c8340SDag-Erling Smørgrav struct stat sb; 1414af12a3e7SDag-Erling Smørgrav 1415af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP 1416b15c8340SDag-Erling Smørgrav if (login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid) 1417b15c8340SDag-Erling Smørgrav return; 1418b15c8340SDag-Erling Smørgrav nl = login_getcapstr(lc, "nologin", def_nl, def_nl); 1419af12a3e7SDag-Erling Smørgrav #else 1420b15c8340SDag-Erling Smørgrav if (pw->pw_uid == 0) 1421b15c8340SDag-Erling Smørgrav return; 1422b15c8340SDag-Erling Smørgrav nl = def_nl; 1423af12a3e7SDag-Erling Smørgrav #endif 1424b15c8340SDag-Erling Smørgrav if (stat(nl, &sb) == -1) { 1425b15c8340SDag-Erling Smørgrav if (nl != def_nl) 1426b15c8340SDag-Erling Smørgrav xfree(nl); 1427b15c8340SDag-Erling Smørgrav return; 1428b15c8340SDag-Erling Smørgrav } 1429b15c8340SDag-Erling Smørgrav 1430b15c8340SDag-Erling Smørgrav /* /etc/nologin exists. Print its contents if we can and exit. */ 1431b15c8340SDag-Erling Smørgrav logit("User %.100s not allowed because %s exists", pw->pw_name, nl); 1432b15c8340SDag-Erling Smørgrav if ((f = fopen(nl, "r")) != NULL) { 1433af12a3e7SDag-Erling Smørgrav while (fgets(buf, sizeof(buf), f)) 1434af12a3e7SDag-Erling Smørgrav fputs(buf, stderr); 1435af12a3e7SDag-Erling Smørgrav fclose(f); 1436af12a3e7SDag-Erling Smørgrav } 1437b15c8340SDag-Erling Smørgrav exit(254); 1438af12a3e7SDag-Erling Smørgrav } 1439af12a3e7SDag-Erling Smørgrav 1440d4af9e69SDag-Erling Smørgrav /* 1441d4af9e69SDag-Erling Smørgrav * Chroot into a directory after checking it for safety: all path components 1442d4af9e69SDag-Erling Smørgrav * must be root-owned directories with strict permissions. 1443d4af9e69SDag-Erling Smørgrav */ 1444d4af9e69SDag-Erling Smørgrav static void 1445d4af9e69SDag-Erling Smørgrav safely_chroot(const char *path, uid_t uid) 1446d4af9e69SDag-Erling Smørgrav { 1447d4af9e69SDag-Erling Smørgrav const char *cp; 1448d4af9e69SDag-Erling Smørgrav char component[MAXPATHLEN]; 1449d4af9e69SDag-Erling Smørgrav struct stat st; 1450d4af9e69SDag-Erling Smørgrav 1451d4af9e69SDag-Erling Smørgrav if (*path != '/') 1452d4af9e69SDag-Erling Smørgrav fatal("chroot path does not begin at root"); 1453d4af9e69SDag-Erling Smørgrav if (strlen(path) >= sizeof(component)) 1454d4af9e69SDag-Erling Smørgrav fatal("chroot path too long"); 1455d4af9e69SDag-Erling Smørgrav 1456d4af9e69SDag-Erling Smørgrav /* 1457d4af9e69SDag-Erling Smørgrav * Descend the path, checking that each component is a 1458d4af9e69SDag-Erling Smørgrav * root-owned directory with strict permissions. 1459d4af9e69SDag-Erling Smørgrav */ 1460d4af9e69SDag-Erling Smørgrav for (cp = path; cp != NULL;) { 1461d4af9e69SDag-Erling Smørgrav if ((cp = strchr(cp, '/')) == NULL) 1462d4af9e69SDag-Erling Smørgrav strlcpy(component, path, sizeof(component)); 1463d4af9e69SDag-Erling Smørgrav else { 1464d4af9e69SDag-Erling Smørgrav cp++; 1465d4af9e69SDag-Erling Smørgrav memcpy(component, path, cp - path); 1466d4af9e69SDag-Erling Smørgrav component[cp - path] = '\0'; 1467d4af9e69SDag-Erling Smørgrav } 1468d4af9e69SDag-Erling Smørgrav 1469d4af9e69SDag-Erling Smørgrav debug3("%s: checking '%s'", __func__, component); 1470d4af9e69SDag-Erling Smørgrav 1471d4af9e69SDag-Erling Smørgrav if (stat(component, &st) != 0) 1472d4af9e69SDag-Erling Smørgrav fatal("%s: stat(\"%s\"): %s", __func__, 1473d4af9e69SDag-Erling Smørgrav component, strerror(errno)); 1474d4af9e69SDag-Erling Smørgrav if (st.st_uid != 0 || (st.st_mode & 022) != 0) 1475d4af9e69SDag-Erling Smørgrav fatal("bad ownership or modes for chroot " 1476d4af9e69SDag-Erling Smørgrav "directory %s\"%s\"", 1477d4af9e69SDag-Erling Smørgrav cp == NULL ? "" : "component ", component); 1478d4af9e69SDag-Erling Smørgrav if (!S_ISDIR(st.st_mode)) 1479d4af9e69SDag-Erling Smørgrav fatal("chroot path %s\"%s\" is not a directory", 1480d4af9e69SDag-Erling Smørgrav cp == NULL ? "" : "component ", component); 1481d4af9e69SDag-Erling Smørgrav 1482d4af9e69SDag-Erling Smørgrav } 1483d4af9e69SDag-Erling Smørgrav 1484d4af9e69SDag-Erling Smørgrav if (chdir(path) == -1) 1485d4af9e69SDag-Erling Smørgrav fatal("Unable to chdir to chroot path \"%s\": " 1486d4af9e69SDag-Erling Smørgrav "%s", path, strerror(errno)); 1487d4af9e69SDag-Erling Smørgrav if (chroot(path) == -1) 1488d4af9e69SDag-Erling Smørgrav fatal("chroot(\"%s\"): %s", path, strerror(errno)); 1489d4af9e69SDag-Erling Smørgrav if (chdir("/") == -1) 1490d4af9e69SDag-Erling Smørgrav fatal("%s: chdir(/) after chroot: %s", 1491d4af9e69SDag-Erling Smørgrav __func__, strerror(errno)); 1492d4af9e69SDag-Erling Smørgrav verbose("Changed root directory to \"%s\"", path); 1493d4af9e69SDag-Erling Smørgrav } 1494d4af9e69SDag-Erling Smørgrav 1495af12a3e7SDag-Erling Smørgrav /* Set login name, uid, gid, and groups. */ 1496989dd127SDag-Erling Smørgrav void 149780628bacSDag-Erling Smørgrav do_setusercontext(struct passwd *pw) 1498af12a3e7SDag-Erling Smørgrav { 1499d4af9e69SDag-Erling Smørgrav char *chroot_path, *tmp; 1500d4af9e69SDag-Erling Smørgrav 1501d4af9e69SDag-Erling Smørgrav #ifdef WITH_SELINUX 1502d4af9e69SDag-Erling Smørgrav /* Cache selinux status for later use */ 1503d4af9e69SDag-Erling Smørgrav (void)ssh_selinux_enabled(); 1504d4af9e69SDag-Erling Smørgrav #endif 1505d4af9e69SDag-Erling Smørgrav 1506e73e9afaSDag-Erling Smørgrav #ifndef HAVE_CYGWIN 1507e73e9afaSDag-Erling Smørgrav if (getuid() == 0 || geteuid() == 0) 1508989dd127SDag-Erling Smørgrav #endif /* HAVE_CYGWIN */ 1509e73e9afaSDag-Erling Smørgrav { 1510989dd127SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP 1511a82e551fSDag-Erling Smørgrav # ifdef __bsdi__ 1512a82e551fSDag-Erling Smørgrav setpgid(0, 0); 1513a82e551fSDag-Erling Smørgrav # endif 15141ec0d754SDag-Erling Smørgrav # ifdef USE_PAM 15151ec0d754SDag-Erling Smørgrav if (options.use_pam) { 1516d4af9e69SDag-Erling Smørgrav do_pam_setcred(use_privsep); 15171ec0d754SDag-Erling Smørgrav } 15181ec0d754SDag-Erling Smørgrav # endif /* USE_PAM */ 1519989dd127SDag-Erling Smørgrav if (setusercontext(lc, pw, pw->pw_uid, 1520d4af9e69SDag-Erling Smørgrav (LOGIN_SETALL & ~(LOGIN_SETENV|LOGIN_SETPATH|LOGIN_SETUSER))) < 0) { 1521989dd127SDag-Erling Smørgrav perror("unable to set user context"); 1522989dd127SDag-Erling Smørgrav exit(1); 1523989dd127SDag-Erling Smørgrav } 1524989dd127SDag-Erling Smørgrav #else 1525989dd127SDag-Erling Smørgrav # if defined(HAVE_GETLUID) && defined(HAVE_SETLUID) 1526989dd127SDag-Erling Smørgrav /* Sets login uid for accounting */ 1527989dd127SDag-Erling Smørgrav if (getluid() == -1 && setluid(pw->pw_uid) == -1) 1528989dd127SDag-Erling Smørgrav error("setluid: %s", strerror(errno)); 1529989dd127SDag-Erling Smørgrav # endif /* defined(HAVE_GETLUID) && defined(HAVE_SETLUID) */ 1530989dd127SDag-Erling Smørgrav 1531af12a3e7SDag-Erling Smørgrav if (setlogin(pw->pw_name) < 0) 1532af12a3e7SDag-Erling Smørgrav error("setlogin failed: %s", strerror(errno)); 1533af12a3e7SDag-Erling Smørgrav if (setgid(pw->pw_gid) < 0) { 1534af12a3e7SDag-Erling Smørgrav perror("setgid"); 1535af12a3e7SDag-Erling Smørgrav exit(1); 1536af12a3e7SDag-Erling Smørgrav } 1537af12a3e7SDag-Erling Smørgrav /* Initialize the group list. */ 1538af12a3e7SDag-Erling Smørgrav if (initgroups(pw->pw_name, pw->pw_gid) < 0) { 1539af12a3e7SDag-Erling Smørgrav perror("initgroups"); 1540af12a3e7SDag-Erling Smørgrav exit(1); 1541af12a3e7SDag-Erling Smørgrav } 1542af12a3e7SDag-Erling Smørgrav endgrent(); 1543989dd127SDag-Erling Smørgrav # ifdef USE_PAM 1544989dd127SDag-Erling Smørgrav /* 1545989dd127SDag-Erling Smørgrav * PAM credentials may take the form of supplementary groups. 1546989dd127SDag-Erling Smørgrav * These will have been wiped by the above initgroups() call. 1547989dd127SDag-Erling Smørgrav * Reestablish them here. 1548989dd127SDag-Erling Smørgrav */ 1549cf2b5f3bSDag-Erling Smørgrav if (options.use_pam) { 1550d4af9e69SDag-Erling Smørgrav do_pam_setcred(use_privsep); 1551cf2b5f3bSDag-Erling Smørgrav } 1552989dd127SDag-Erling Smørgrav # endif /* USE_PAM */ 1553989dd127SDag-Erling Smørgrav # if defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) 1554989dd127SDag-Erling Smørgrav irix_setusercontext(pw); 1555989dd127SDag-Erling Smørgrav # endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */ 1556a82e551fSDag-Erling Smørgrav # ifdef _AIX 1557f388f5efSDag-Erling Smørgrav aix_usrinfo(pw); 1558a82e551fSDag-Erling Smørgrav # endif /* _AIX */ 1559d4af9e69SDag-Erling Smørgrav # ifdef USE_LIBIAF 1560d4ecd108SDag-Erling Smørgrav if (set_id(pw->pw_name) != 0) { 1561d4ecd108SDag-Erling Smørgrav exit(1); 1562d4ecd108SDag-Erling Smørgrav } 1563d4af9e69SDag-Erling Smørgrav # endif /* USE_LIBIAF */ 1564d4af9e69SDag-Erling Smørgrav #endif 1565b15c8340SDag-Erling Smørgrav #ifdef HAVE_SETPCRED 1566b15c8340SDag-Erling Smørgrav /* 1567b15c8340SDag-Erling Smørgrav * If we have a chroot directory, we set all creds except real 1568b15c8340SDag-Erling Smørgrav * uid which we will need for chroot. If we don't have a 1569b15c8340SDag-Erling Smørgrav * chroot directory, we don't override anything. 1570b15c8340SDag-Erling Smørgrav */ 1571b15c8340SDag-Erling Smørgrav { 1572b15c8340SDag-Erling Smørgrav char **creds = NULL, *chroot_creds[] = 1573b15c8340SDag-Erling Smørgrav { "REAL_USER=root", NULL }; 1574b15c8340SDag-Erling Smørgrav 1575b15c8340SDag-Erling Smørgrav if (options.chroot_directory != NULL && 1576b15c8340SDag-Erling Smørgrav strcasecmp(options.chroot_directory, "none") != 0) 1577b15c8340SDag-Erling Smørgrav creds = chroot_creds; 1578b15c8340SDag-Erling Smørgrav 1579b15c8340SDag-Erling Smørgrav if (setpcred(pw->pw_name, creds) == -1) 1580b15c8340SDag-Erling Smørgrav fatal("Failed to set process credentials"); 1581b15c8340SDag-Erling Smørgrav } 1582b15c8340SDag-Erling Smørgrav #endif /* HAVE_SETPCRED */ 1583d4af9e69SDag-Erling Smørgrav 1584d4af9e69SDag-Erling Smørgrav if (options.chroot_directory != NULL && 1585d4af9e69SDag-Erling Smørgrav strcasecmp(options.chroot_directory, "none") != 0) { 1586d4af9e69SDag-Erling Smørgrav tmp = tilde_expand_filename(options.chroot_directory, 1587d4af9e69SDag-Erling Smørgrav pw->pw_uid); 1588d4af9e69SDag-Erling Smørgrav chroot_path = percent_expand(tmp, "h", pw->pw_dir, 1589d4af9e69SDag-Erling Smørgrav "u", pw->pw_name, (char *)NULL); 1590d4af9e69SDag-Erling Smørgrav safely_chroot(chroot_path, pw->pw_uid); 1591d4af9e69SDag-Erling Smørgrav free(tmp); 1592d4af9e69SDag-Erling Smørgrav free(chroot_path); 1593d4af9e69SDag-Erling Smørgrav } 1594d4af9e69SDag-Erling Smørgrav 1595d4af9e69SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP 1596d4af9e69SDag-Erling Smørgrav if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUSER) < 0) { 1597d4af9e69SDag-Erling Smørgrav perror("unable to set user context (setuser)"); 1598d4af9e69SDag-Erling Smørgrav exit(1); 1599d4af9e69SDag-Erling Smørgrav } 1600d4af9e69SDag-Erling Smørgrav #else 1601af12a3e7SDag-Erling Smørgrav /* Permanently switch to the desired uid. */ 1602af12a3e7SDag-Erling Smørgrav permanently_set_uid(pw); 1603989dd127SDag-Erling Smørgrav #endif 1604af12a3e7SDag-Erling Smørgrav } 1605e73e9afaSDag-Erling Smørgrav 1606af12a3e7SDag-Erling Smørgrav if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) 1607af12a3e7SDag-Erling Smørgrav fatal("Failed to set uids to %u.", (u_int) pw->pw_uid); 1608333ee039SDag-Erling Smørgrav 1609333ee039SDag-Erling Smørgrav #ifdef WITH_SELINUX 1610333ee039SDag-Erling Smørgrav ssh_selinux_setup_exec_context(pw->pw_name); 1611333ee039SDag-Erling Smørgrav #endif 161280628bacSDag-Erling Smørgrav } 161380628bacSDag-Erling Smørgrav 161480628bacSDag-Erling Smørgrav static void 16151ec0d754SDag-Erling Smørgrav do_pwchange(Session *s) 16161ec0d754SDag-Erling Smørgrav { 161721e764dfSDag-Erling Smørgrav fflush(NULL); 16181ec0d754SDag-Erling Smørgrav fprintf(stderr, "WARNING: Your password has expired.\n"); 16191ec0d754SDag-Erling Smørgrav if (s->ttyfd != -1) { 16201ec0d754SDag-Erling Smørgrav fprintf(stderr, 16211ec0d754SDag-Erling Smørgrav "You must change your password now and login again!\n"); 1622aa49c926SDag-Erling Smørgrav #ifdef PASSWD_NEEDS_USERNAME 1623aa49c926SDag-Erling Smørgrav execl(_PATH_PASSWD_PROG, "passwd", s->pw->pw_name, 1624aa49c926SDag-Erling Smørgrav (char *)NULL); 1625aa49c926SDag-Erling Smørgrav #else 16261ec0d754SDag-Erling Smørgrav execl(_PATH_PASSWD_PROG, "passwd", (char *)NULL); 1627aa49c926SDag-Erling Smørgrav #endif 16281ec0d754SDag-Erling Smørgrav perror("passwd"); 16291ec0d754SDag-Erling Smørgrav } else { 16301ec0d754SDag-Erling Smørgrav fprintf(stderr, 16311ec0d754SDag-Erling Smørgrav "Password change required but no TTY available.\n"); 16321ec0d754SDag-Erling Smørgrav } 16331ec0d754SDag-Erling Smørgrav exit(1); 16341ec0d754SDag-Erling Smørgrav } 16351ec0d754SDag-Erling Smørgrav 16361ec0d754SDag-Erling Smørgrav static void 163780628bacSDag-Erling Smørgrav launch_login(struct passwd *pw, const char *hostname) 163880628bacSDag-Erling Smørgrav { 163980628bacSDag-Erling Smørgrav /* Launch login(1). */ 164080628bacSDag-Erling Smørgrav 1641989dd127SDag-Erling Smørgrav execl(LOGIN_PROGRAM, "login", "-h", hostname, 1642989dd127SDag-Erling Smørgrav #ifdef xxxLOGIN_NEEDS_TERM 1643989dd127SDag-Erling Smørgrav (s->term ? s->term : "unknown"), 1644989dd127SDag-Erling Smørgrav #endif /* LOGIN_NEEDS_TERM */ 1645989dd127SDag-Erling Smørgrav #ifdef LOGIN_NO_ENDOPT 1646989dd127SDag-Erling Smørgrav "-p", "-f", pw->pw_name, (char *)NULL); 1647989dd127SDag-Erling Smørgrav #else 164880628bacSDag-Erling Smørgrav "-p", "-f", "--", pw->pw_name, (char *)NULL); 1649989dd127SDag-Erling Smørgrav #endif 165080628bacSDag-Erling Smørgrav 165180628bacSDag-Erling Smørgrav /* Login couldn't be executed, die. */ 165280628bacSDag-Erling Smørgrav 165380628bacSDag-Erling Smørgrav perror("login"); 165480628bacSDag-Erling Smørgrav exit(1); 1655af12a3e7SDag-Erling Smørgrav } 1656af12a3e7SDag-Erling Smørgrav 16571ec0d754SDag-Erling Smørgrav static void 16581ec0d754SDag-Erling Smørgrav child_close_fds(void) 16591ec0d754SDag-Erling Smørgrav { 16601ec0d754SDag-Erling Smørgrav int i; 16611ec0d754SDag-Erling Smørgrav 16621ec0d754SDag-Erling Smørgrav if (packet_get_connection_in() == packet_get_connection_out()) 16631ec0d754SDag-Erling Smørgrav close(packet_get_connection_in()); 16641ec0d754SDag-Erling Smørgrav else { 16651ec0d754SDag-Erling Smørgrav close(packet_get_connection_in()); 16661ec0d754SDag-Erling Smørgrav close(packet_get_connection_out()); 16671ec0d754SDag-Erling Smørgrav } 16681ec0d754SDag-Erling Smørgrav /* 16691ec0d754SDag-Erling Smørgrav * Close all descriptors related to channels. They will still remain 16701ec0d754SDag-Erling Smørgrav * open in the parent. 16711ec0d754SDag-Erling Smørgrav */ 16721ec0d754SDag-Erling Smørgrav /* XXX better use close-on-exec? -markus */ 16731ec0d754SDag-Erling Smørgrav channel_close_all(); 16741ec0d754SDag-Erling Smørgrav 16751ec0d754SDag-Erling Smørgrav /* 16761ec0d754SDag-Erling Smørgrav * Close any extra file descriptors. Note that there may still be 16771ec0d754SDag-Erling Smørgrav * descriptors left by system functions. They will be closed later. 16781ec0d754SDag-Erling Smørgrav */ 16791ec0d754SDag-Erling Smørgrav endpwent(); 16801ec0d754SDag-Erling Smørgrav 16811ec0d754SDag-Erling Smørgrav /* 1682b74df5b2SDag-Erling Smørgrav * Close any extra open file descriptors so that we don't have them 16831ec0d754SDag-Erling Smørgrav * hanging around in clients. Note that we want to do this after 16841ec0d754SDag-Erling Smørgrav * initgroups, because at least on Solaris 2.3 it leaves file 16851ec0d754SDag-Erling Smørgrav * descriptors open. 16861ec0d754SDag-Erling Smørgrav */ 16871ec0d754SDag-Erling Smørgrav for (i = 3; i < 64; i++) 16881ec0d754SDag-Erling Smørgrav close(i); 16891ec0d754SDag-Erling Smørgrav } 16901ec0d754SDag-Erling Smørgrav 1691af12a3e7SDag-Erling Smørgrav /* 1692af12a3e7SDag-Erling Smørgrav * Performs common processing for the child, such as setting up the 1693af12a3e7SDag-Erling Smørgrav * environment, closing extra file descriptors, setting the user and group 1694af12a3e7SDag-Erling Smørgrav * ids, and executing the command or shell. 1695af12a3e7SDag-Erling Smørgrav */ 1696d4af9e69SDag-Erling Smørgrav #define ARGV_MAX 10 1697af12a3e7SDag-Erling Smørgrav void 1698af12a3e7SDag-Erling Smørgrav do_child(Session *s, const char *command) 1699af12a3e7SDag-Erling Smørgrav { 1700af12a3e7SDag-Erling Smørgrav extern char **environ; 1701989dd127SDag-Erling Smørgrav char **env; 1702d4af9e69SDag-Erling Smørgrav char *argv[ARGV_MAX]; 1703af12a3e7SDag-Erling Smørgrav const char *shell, *shell0, *hostname = NULL; 1704af12a3e7SDag-Erling Smørgrav struct passwd *pw = s->pw; 1705d4af9e69SDag-Erling Smørgrav int r = 0; 1706af12a3e7SDag-Erling Smørgrav 1707af12a3e7SDag-Erling Smørgrav /* remove hostkey from the child's memory */ 1708af12a3e7SDag-Erling Smørgrav destroy_sensitive_data(); 1709af12a3e7SDag-Erling Smørgrav 17101ec0d754SDag-Erling Smørgrav /* Force a password change */ 17111ec0d754SDag-Erling Smørgrav if (s->authctxt->force_pwchange) { 17121ec0d754SDag-Erling Smørgrav do_setusercontext(pw); 17131ec0d754SDag-Erling Smørgrav child_close_fds(); 17141ec0d754SDag-Erling Smørgrav do_pwchange(s); 17151ec0d754SDag-Erling Smørgrav exit(1); 17161ec0d754SDag-Erling Smørgrav } 17171ec0d754SDag-Erling Smørgrav 1718af12a3e7SDag-Erling Smørgrav /* login(1) is only called if we execute the login shell */ 1719af12a3e7SDag-Erling Smørgrav if (options.use_login && command != NULL) 1720af12a3e7SDag-Erling Smørgrav options.use_login = 0; 1721af12a3e7SDag-Erling Smørgrav 1722f388f5efSDag-Erling Smørgrav #ifdef _UNICOS 1723f388f5efSDag-Erling Smørgrav cray_setup(pw->pw_uid, pw->pw_name, command); 1724f388f5efSDag-Erling Smørgrav #endif /* _UNICOS */ 1725f388f5efSDag-Erling Smørgrav 1726af12a3e7SDag-Erling Smørgrav /* 1727af12a3e7SDag-Erling Smørgrav * Login(1) does this as well, and it needs uid 0 for the "-h" 1728af12a3e7SDag-Erling Smørgrav * switch, so we let login(1) to this for us. 1729af12a3e7SDag-Erling Smørgrav */ 1730af12a3e7SDag-Erling Smørgrav if (!options.use_login) { 1731989dd127SDag-Erling Smørgrav #ifdef HAVE_OSF_SIA 1732e73e9afaSDag-Erling Smørgrav session_setup_sia(pw, s->ttyfd == -1 ? NULL : s->tty); 1733989dd127SDag-Erling Smørgrav if (!check_quietlogin(s, command)) 1734989dd127SDag-Erling Smørgrav do_motd(); 1735989dd127SDag-Erling Smørgrav #else /* HAVE_OSF_SIA */ 1736b74df5b2SDag-Erling Smørgrav /* When PAM is enabled we rely on it to do the nologin check */ 1737b74df5b2SDag-Erling Smørgrav if (!options.use_pam) 1738af12a3e7SDag-Erling Smørgrav do_nologin(pw); 1739989dd127SDag-Erling Smørgrav do_setusercontext(pw); 174021e764dfSDag-Erling Smørgrav /* 174121e764dfSDag-Erling Smørgrav * PAM session modules in do_setusercontext may have 174221e764dfSDag-Erling Smørgrav * generated messages, so if this in an interactive 174321e764dfSDag-Erling Smørgrav * login then display them too. 174421e764dfSDag-Erling Smørgrav */ 1745aa49c926SDag-Erling Smørgrav if (!check_quietlogin(s, command)) 174621e764dfSDag-Erling Smørgrav display_loginmsg(); 1747989dd127SDag-Erling Smørgrav #endif /* HAVE_OSF_SIA */ 1748af12a3e7SDag-Erling Smørgrav } 1749af12a3e7SDag-Erling Smørgrav 1750aa49c926SDag-Erling Smørgrav #ifdef USE_PAM 1751aa49c926SDag-Erling Smørgrav if (options.use_pam && !options.use_login && !is_pam_session_open()) { 1752aa49c926SDag-Erling Smørgrav debug3("PAM session not opened, exiting"); 1753aa49c926SDag-Erling Smørgrav display_loginmsg(); 1754aa49c926SDag-Erling Smørgrav exit(254); 1755aa49c926SDag-Erling Smørgrav } 1756aa49c926SDag-Erling Smørgrav #endif 1757aa49c926SDag-Erling Smørgrav 1758af12a3e7SDag-Erling Smørgrav /* 1759af12a3e7SDag-Erling Smørgrav * Get the shell from the password data. An empty shell field is 1760af12a3e7SDag-Erling Smørgrav * legal, and means /bin/sh. 1761af12a3e7SDag-Erling Smørgrav */ 1762af12a3e7SDag-Erling Smørgrav shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; 1763e73e9afaSDag-Erling Smørgrav 1764e73e9afaSDag-Erling Smørgrav /* 1765e73e9afaSDag-Erling Smørgrav * Make sure $SHELL points to the shell from the password file, 1766e73e9afaSDag-Erling Smørgrav * even if shell is overridden from login.conf 1767e73e9afaSDag-Erling Smørgrav */ 1768e73e9afaSDag-Erling Smørgrav env = do_setup_env(s, shell); 1769e73e9afaSDag-Erling Smørgrav 1770af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP 1771af12a3e7SDag-Erling Smørgrav shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell); 1772af12a3e7SDag-Erling Smørgrav #endif 1773af12a3e7SDag-Erling Smørgrav 1774af12a3e7SDag-Erling Smørgrav /* we have to stash the hostname before we close our socket. */ 1775af12a3e7SDag-Erling Smørgrav if (options.use_login) 1776af12a3e7SDag-Erling Smørgrav hostname = get_remote_name_or_ip(utmp_len, 1777cf2b5f3bSDag-Erling Smørgrav options.use_dns); 1778af12a3e7SDag-Erling Smørgrav /* 1779af12a3e7SDag-Erling Smørgrav * Close the connection descriptors; note that this is the child, and 1780af12a3e7SDag-Erling Smørgrav * the server will still have the socket open, and it is important 1781af12a3e7SDag-Erling Smørgrav * that we do not shutdown it. Note that the descriptors cannot be 1782af12a3e7SDag-Erling Smørgrav * closed before building the environment, as we call 1783af12a3e7SDag-Erling Smørgrav * get_remote_ipaddr there. 1784af12a3e7SDag-Erling Smørgrav */ 17851ec0d754SDag-Erling Smørgrav child_close_fds(); 1786af12a3e7SDag-Erling Smørgrav 1787af12a3e7SDag-Erling Smørgrav /* 1788af12a3e7SDag-Erling Smørgrav * Must take new environment into use so that .ssh/rc, 1789af12a3e7SDag-Erling Smørgrav * /etc/ssh/sshrc and xauth are run in the proper environment. 1790af12a3e7SDag-Erling Smørgrav */ 1791af12a3e7SDag-Erling Smørgrav environ = env; 1792af12a3e7SDag-Erling Smørgrav 17931ec0d754SDag-Erling Smørgrav #if defined(KRB5) && defined(USE_AFS) 17941ec0d754SDag-Erling Smørgrav /* 17951ec0d754SDag-Erling Smørgrav * At this point, we check to see if AFS is active and if we have 17961ec0d754SDag-Erling Smørgrav * a valid Kerberos 5 TGT. If so, it seems like a good idea to see 17971ec0d754SDag-Erling Smørgrav * if we can (and need to) extend the ticket into an AFS token. If 17981ec0d754SDag-Erling Smørgrav * we don't do this, we run into potential problems if the user's 17991ec0d754SDag-Erling Smørgrav * home directory is in AFS and it's not world-readable. 18001ec0d754SDag-Erling Smørgrav */ 18011ec0d754SDag-Erling Smørgrav 18021ec0d754SDag-Erling Smørgrav if (options.kerberos_get_afs_token && k_hasafs() && 18031ec0d754SDag-Erling Smørgrav (s->authctxt->krb5_ctx != NULL)) { 18041ec0d754SDag-Erling Smørgrav char cell[64]; 18051ec0d754SDag-Erling Smørgrav 18061ec0d754SDag-Erling Smørgrav debug("Getting AFS token"); 18071ec0d754SDag-Erling Smørgrav 18081ec0d754SDag-Erling Smørgrav k_setpag(); 18091ec0d754SDag-Erling Smørgrav 18101ec0d754SDag-Erling Smørgrav if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0) 18111ec0d754SDag-Erling Smørgrav krb5_afslog(s->authctxt->krb5_ctx, 18121ec0d754SDag-Erling Smørgrav s->authctxt->krb5_fwd_ccache, cell, NULL); 18131ec0d754SDag-Erling Smørgrav 18141ec0d754SDag-Erling Smørgrav krb5_afslog_home(s->authctxt->krb5_ctx, 18151ec0d754SDag-Erling Smørgrav s->authctxt->krb5_fwd_ccache, NULL, NULL, pw->pw_dir); 18161ec0d754SDag-Erling Smørgrav } 18171ec0d754SDag-Erling Smørgrav #endif 18181ec0d754SDag-Erling Smørgrav 1819b74df5b2SDag-Erling Smørgrav /* Change current directory to the user's home directory. */ 1820af12a3e7SDag-Erling Smørgrav if (chdir(pw->pw_dir) < 0) { 1821d4af9e69SDag-Erling Smørgrav /* Suppress missing homedir warning for chroot case */ 1822af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP 1823d4af9e69SDag-Erling Smørgrav r = login_getcapbool(lc, "requirehome", 0); 1824af12a3e7SDag-Erling Smørgrav #endif 1825d4af9e69SDag-Erling Smørgrav if (r || options.chroot_directory == NULL) 1826d4af9e69SDag-Erling Smørgrav fprintf(stderr, "Could not chdir to home " 1827d4af9e69SDag-Erling Smørgrav "directory %s: %s\n", pw->pw_dir, 1828d4af9e69SDag-Erling Smørgrav strerror(errno)); 1829d4af9e69SDag-Erling Smørgrav if (r) 1830d4af9e69SDag-Erling Smørgrav exit(1); 1831af12a3e7SDag-Erling Smørgrav } 1832af12a3e7SDag-Erling Smørgrav 1833d4af9e69SDag-Erling Smørgrav closefrom(STDERR_FILENO + 1); 1834d4af9e69SDag-Erling Smørgrav 1835af12a3e7SDag-Erling Smørgrav if (!options.use_login) 1836af12a3e7SDag-Erling Smørgrav do_rc_files(s, shell); 1837af12a3e7SDag-Erling Smørgrav 1838ca3176e7SBrian Feldman /* restore SIGPIPE for child */ 1839ca3176e7SBrian Feldman signal(SIGPIPE, SIG_DFL); 1840ca3176e7SBrian Feldman 1841b15c8340SDag-Erling Smørgrav if (s->is_subsystem == SUBSYSTEM_INT_SFTP_ERROR) { 1842b15c8340SDag-Erling Smørgrav printf("This service allows sftp connections only.\n"); 1843b15c8340SDag-Erling Smørgrav fflush(NULL); 1844b15c8340SDag-Erling Smørgrav exit(1); 1845b15c8340SDag-Erling Smørgrav } else if (s->is_subsystem == SUBSYSTEM_INT_SFTP) { 1846d4af9e69SDag-Erling Smørgrav extern int optind, optreset; 1847d4af9e69SDag-Erling Smørgrav int i; 1848d4af9e69SDag-Erling Smørgrav char *p, *args; 1849d4af9e69SDag-Erling Smørgrav 18507aee6ffeSDag-Erling Smørgrav setproctitle("%s@%s", s->pw->pw_name, INTERNAL_SFTP_NAME); 1851cce7d346SDag-Erling Smørgrav args = xstrdup(command ? command : "sftp-server"); 1852d4af9e69SDag-Erling Smørgrav for (i = 0, (p = strtok(args, " ")); p; (p = strtok(NULL, " "))) 1853d4af9e69SDag-Erling Smørgrav if (i < ARGV_MAX - 1) 1854d4af9e69SDag-Erling Smørgrav argv[i++] = p; 1855d4af9e69SDag-Erling Smørgrav argv[i] = NULL; 1856d4af9e69SDag-Erling Smørgrav optind = optreset = 1; 1857d4af9e69SDag-Erling Smørgrav __progname = argv[0]; 1858b15c8340SDag-Erling Smørgrav #ifdef WITH_SELINUX 1859b15c8340SDag-Erling Smørgrav ssh_selinux_change_context("sftpd_t"); 1860b15c8340SDag-Erling Smørgrav #endif 1861d4af9e69SDag-Erling Smørgrav exit(sftp_server_main(i, argv, s->pw)); 1862d4af9e69SDag-Erling Smørgrav } 1863d4af9e69SDag-Erling Smørgrav 1864b15c8340SDag-Erling Smørgrav fflush(NULL); 1865b15c8340SDag-Erling Smørgrav 1866af12a3e7SDag-Erling Smørgrav if (options.use_login) { 186780628bacSDag-Erling Smørgrav launch_login(pw, hostname); 186880628bacSDag-Erling Smørgrav /* NEVERREACHED */ 1869af12a3e7SDag-Erling Smørgrav } 1870af12a3e7SDag-Erling Smørgrav 1871af12a3e7SDag-Erling Smørgrav /* Get the last component of the shell name. */ 1872af12a3e7SDag-Erling Smørgrav if ((shell0 = strrchr(shell, '/')) != NULL) 1873af12a3e7SDag-Erling Smørgrav shell0++; 1874af12a3e7SDag-Erling Smørgrav else 1875af12a3e7SDag-Erling Smørgrav shell0 = shell; 1876af12a3e7SDag-Erling Smørgrav 1877a04a10f8SKris Kennaway /* 1878a04a10f8SKris Kennaway * If we have no command, execute the shell. In this case, the shell 1879a04a10f8SKris Kennaway * name to be passed in argv[0] is preceded by '-' to indicate that 1880a04a10f8SKris Kennaway * this is a login shell. 1881a04a10f8SKris Kennaway */ 1882a04a10f8SKris Kennaway if (!command) { 1883af12a3e7SDag-Erling Smørgrav char argv0[256]; 1884a04a10f8SKris Kennaway 1885a04a10f8SKris Kennaway /* Start the shell. Set initial character to '-'. */ 1886af12a3e7SDag-Erling Smørgrav argv0[0] = '-'; 1887af12a3e7SDag-Erling Smørgrav 1888af12a3e7SDag-Erling Smørgrav if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1) 1889af12a3e7SDag-Erling Smørgrav >= sizeof(argv0) - 1) { 1890af12a3e7SDag-Erling Smørgrav errno = EINVAL; 1891af12a3e7SDag-Erling Smørgrav perror(shell); 1892af12a3e7SDag-Erling Smørgrav exit(1); 1893af12a3e7SDag-Erling Smørgrav } 1894a04a10f8SKris Kennaway 1895a04a10f8SKris Kennaway /* Execute the shell. */ 1896af12a3e7SDag-Erling Smørgrav argv[0] = argv0; 1897a04a10f8SKris Kennaway argv[1] = NULL; 1898a04a10f8SKris Kennaway execve(shell, argv, env); 1899a04a10f8SKris Kennaway 1900a04a10f8SKris Kennaway /* Executing the shell failed. */ 1901a04a10f8SKris Kennaway perror(shell); 1902a04a10f8SKris Kennaway exit(1); 1903a04a10f8SKris Kennaway } 1904a04a10f8SKris Kennaway /* 1905a04a10f8SKris Kennaway * Execute the command using the user's shell. This uses the -c 1906a04a10f8SKris Kennaway * option to execute the command. 1907a04a10f8SKris Kennaway */ 1908af12a3e7SDag-Erling Smørgrav argv[0] = (char *) shell0; 1909a04a10f8SKris Kennaway argv[1] = "-c"; 1910a04a10f8SKris Kennaway argv[2] = (char *) command; 1911a04a10f8SKris Kennaway argv[3] = NULL; 1912a04a10f8SKris Kennaway execve(shell, argv, env); 1913a04a10f8SKris Kennaway perror(shell); 1914a04a10f8SKris Kennaway exit(1); 1915a04a10f8SKris Kennaway } 1916a04a10f8SKris Kennaway 1917d4af9e69SDag-Erling Smørgrav void 1918d4af9e69SDag-Erling Smørgrav session_unused(int id) 1919d4af9e69SDag-Erling Smørgrav { 1920d4af9e69SDag-Erling Smørgrav debug3("%s: session id %d unused", __func__, id); 1921d4af9e69SDag-Erling Smørgrav if (id >= options.max_sessions || 1922d4af9e69SDag-Erling Smørgrav id >= sessions_nalloc) { 1923d4af9e69SDag-Erling Smørgrav fatal("%s: insane session id %d (max %d nalloc %d)", 1924d4af9e69SDag-Erling Smørgrav __func__, id, options.max_sessions, sessions_nalloc); 1925d4af9e69SDag-Erling Smørgrav } 1926d4af9e69SDag-Erling Smørgrav bzero(&sessions[id], sizeof(*sessions)); 1927d4af9e69SDag-Erling Smørgrav sessions[id].self = id; 1928d4af9e69SDag-Erling Smørgrav sessions[id].used = 0; 1929d4af9e69SDag-Erling Smørgrav sessions[id].chanid = -1; 1930d4af9e69SDag-Erling Smørgrav sessions[id].ptyfd = -1; 1931d4af9e69SDag-Erling Smørgrav sessions[id].ttyfd = -1; 1932d4af9e69SDag-Erling Smørgrav sessions[id].ptymaster = -1; 1933d4af9e69SDag-Erling Smørgrav sessions[id].x11_chanids = NULL; 1934d4af9e69SDag-Erling Smørgrav sessions[id].next_unused = sessions_first_unused; 1935d4af9e69SDag-Erling Smørgrav sessions_first_unused = id; 1936d4af9e69SDag-Erling Smørgrav } 1937d4af9e69SDag-Erling Smørgrav 1938a04a10f8SKris Kennaway Session * 1939a04a10f8SKris Kennaway session_new(void) 1940a04a10f8SKris Kennaway { 1941d4af9e69SDag-Erling Smørgrav Session *s, *tmp; 1942d4af9e69SDag-Erling Smørgrav 1943d4af9e69SDag-Erling Smørgrav if (sessions_first_unused == -1) { 1944d4af9e69SDag-Erling Smørgrav if (sessions_nalloc >= options.max_sessions) 1945a04a10f8SKris Kennaway return NULL; 1946d4af9e69SDag-Erling Smørgrav debug2("%s: allocate (allocated %d max %d)", 1947d4af9e69SDag-Erling Smørgrav __func__, sessions_nalloc, options.max_sessions); 1948d4af9e69SDag-Erling Smørgrav tmp = xrealloc(sessions, sessions_nalloc + 1, 1949d4af9e69SDag-Erling Smørgrav sizeof(*sessions)); 1950d4af9e69SDag-Erling Smørgrav if (tmp == NULL) { 1951d4af9e69SDag-Erling Smørgrav error("%s: cannot allocate %d sessions", 1952d4af9e69SDag-Erling Smørgrav __func__, sessions_nalloc + 1); 1953d4af9e69SDag-Erling Smørgrav return NULL; 1954d4af9e69SDag-Erling Smørgrav } 1955d4af9e69SDag-Erling Smørgrav sessions = tmp; 1956d4af9e69SDag-Erling Smørgrav session_unused(sessions_nalloc++); 1957d4af9e69SDag-Erling Smørgrav } 1958d4af9e69SDag-Erling Smørgrav 1959d4af9e69SDag-Erling Smørgrav if (sessions_first_unused >= sessions_nalloc || 1960d4af9e69SDag-Erling Smørgrav sessions_first_unused < 0) { 1961d4af9e69SDag-Erling Smørgrav fatal("%s: insane first_unused %d max %d nalloc %d", 1962d4af9e69SDag-Erling Smørgrav __func__, sessions_first_unused, options.max_sessions, 1963d4af9e69SDag-Erling Smørgrav sessions_nalloc); 1964d4af9e69SDag-Erling Smørgrav } 1965d4af9e69SDag-Erling Smørgrav 1966d4af9e69SDag-Erling Smørgrav s = &sessions[sessions_first_unused]; 1967d4af9e69SDag-Erling Smørgrav if (s->used) { 1968d4af9e69SDag-Erling Smørgrav fatal("%s: session %d already used", 1969d4af9e69SDag-Erling Smørgrav __func__, sessions_first_unused); 1970d4af9e69SDag-Erling Smørgrav } 1971d4af9e69SDag-Erling Smørgrav sessions_first_unused = s->next_unused; 1972d4af9e69SDag-Erling Smørgrav s->used = 1; 1973d4af9e69SDag-Erling Smørgrav s->next_unused = -1; 1974d4af9e69SDag-Erling Smørgrav debug("session_new: session %d", s->self); 1975d4af9e69SDag-Erling Smørgrav 1976d4af9e69SDag-Erling Smørgrav return s; 1977a04a10f8SKris Kennaway } 1978a04a10f8SKris Kennaway 1979af12a3e7SDag-Erling Smørgrav static void 1980a04a10f8SKris Kennaway session_dump(void) 1981a04a10f8SKris Kennaway { 1982a04a10f8SKris Kennaway int i; 1983d4af9e69SDag-Erling Smørgrav for (i = 0; i < sessions_nalloc; i++) { 1984a04a10f8SKris Kennaway Session *s = &sessions[i]; 1985d4af9e69SDag-Erling Smørgrav 1986d4af9e69SDag-Erling Smørgrav debug("dump: used %d next_unused %d session %d %p " 1987d4af9e69SDag-Erling Smørgrav "channel %d pid %ld", 1988a04a10f8SKris Kennaway s->used, 1989d4af9e69SDag-Erling Smørgrav s->next_unused, 1990a04a10f8SKris Kennaway s->self, 1991a04a10f8SKris Kennaway s, 1992a04a10f8SKris Kennaway s->chanid, 199380628bacSDag-Erling Smørgrav (long)s->pid); 1994a04a10f8SKris Kennaway } 1995a04a10f8SKris Kennaway } 1996a04a10f8SKris Kennaway 1997a04a10f8SKris Kennaway int 1998af12a3e7SDag-Erling Smørgrav session_open(Authctxt *authctxt, int chanid) 1999a04a10f8SKris Kennaway { 2000a04a10f8SKris Kennaway Session *s = session_new(); 2001a04a10f8SKris Kennaway debug("session_open: channel %d", chanid); 2002a04a10f8SKris Kennaway if (s == NULL) { 2003a04a10f8SKris Kennaway error("no more sessions"); 2004a04a10f8SKris Kennaway return 0; 2005a04a10f8SKris Kennaway } 2006af12a3e7SDag-Erling Smørgrav s->authctxt = authctxt; 2007af12a3e7SDag-Erling Smørgrav s->pw = authctxt->pw; 20081ec0d754SDag-Erling Smørgrav if (s->pw == NULL || !authctxt->valid) 2009ca3176e7SBrian Feldman fatal("no user for session %d", s->self); 2010a04a10f8SKris Kennaway debug("session_open: session %d: link with channel %d", s->self, chanid); 2011a04a10f8SKris Kennaway s->chanid = chanid; 2012a04a10f8SKris Kennaway return 1; 2013a04a10f8SKris Kennaway } 2014a04a10f8SKris Kennaway 201580628bacSDag-Erling Smørgrav Session * 201680628bacSDag-Erling Smørgrav session_by_tty(char *tty) 201780628bacSDag-Erling Smørgrav { 201880628bacSDag-Erling Smørgrav int i; 2019d4af9e69SDag-Erling Smørgrav for (i = 0; i < sessions_nalloc; i++) { 202080628bacSDag-Erling Smørgrav Session *s = &sessions[i]; 202180628bacSDag-Erling Smørgrav if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) { 202280628bacSDag-Erling Smørgrav debug("session_by_tty: session %d tty %s", i, tty); 202380628bacSDag-Erling Smørgrav return s; 202480628bacSDag-Erling Smørgrav } 202580628bacSDag-Erling Smørgrav } 202680628bacSDag-Erling Smørgrav debug("session_by_tty: unknown tty %.100s", tty); 202780628bacSDag-Erling Smørgrav session_dump(); 202880628bacSDag-Erling Smørgrav return NULL; 202980628bacSDag-Erling Smørgrav } 203080628bacSDag-Erling Smørgrav 2031af12a3e7SDag-Erling Smørgrav static Session * 2032a04a10f8SKris Kennaway session_by_channel(int id) 2033a04a10f8SKris Kennaway { 2034a04a10f8SKris Kennaway int i; 2035d4af9e69SDag-Erling Smørgrav for (i = 0; i < sessions_nalloc; i++) { 2036a04a10f8SKris Kennaway Session *s = &sessions[i]; 2037a04a10f8SKris Kennaway if (s->used && s->chanid == id) { 2038d4af9e69SDag-Erling Smørgrav debug("session_by_channel: session %d channel %d", 2039d4af9e69SDag-Erling Smørgrav i, id); 2040a04a10f8SKris Kennaway return s; 2041a04a10f8SKris Kennaway } 2042a04a10f8SKris Kennaway } 2043a04a10f8SKris Kennaway debug("session_by_channel: unknown channel %d", id); 2044a04a10f8SKris Kennaway session_dump(); 2045a04a10f8SKris Kennaway return NULL; 2046a04a10f8SKris Kennaway } 2047a04a10f8SKris Kennaway 2048af12a3e7SDag-Erling Smørgrav static Session * 2049d4ecd108SDag-Erling Smørgrav session_by_x11_channel(int id) 2050d4ecd108SDag-Erling Smørgrav { 2051d4ecd108SDag-Erling Smørgrav int i, j; 2052d4ecd108SDag-Erling Smørgrav 2053d4af9e69SDag-Erling Smørgrav for (i = 0; i < sessions_nalloc; i++) { 2054d4ecd108SDag-Erling Smørgrav Session *s = &sessions[i]; 2055d4ecd108SDag-Erling Smørgrav 2056d4ecd108SDag-Erling Smørgrav if (s->x11_chanids == NULL || !s->used) 2057d4ecd108SDag-Erling Smørgrav continue; 2058d4ecd108SDag-Erling Smørgrav for (j = 0; s->x11_chanids[j] != -1; j++) { 2059d4ecd108SDag-Erling Smørgrav if (s->x11_chanids[j] == id) { 2060d4ecd108SDag-Erling Smørgrav debug("session_by_x11_channel: session %d " 2061d4ecd108SDag-Erling Smørgrav "channel %d", s->self, id); 2062d4ecd108SDag-Erling Smørgrav return s; 2063d4ecd108SDag-Erling Smørgrav } 2064d4ecd108SDag-Erling Smørgrav } 2065d4ecd108SDag-Erling Smørgrav } 2066d4ecd108SDag-Erling Smørgrav debug("session_by_x11_channel: unknown channel %d", id); 2067d4ecd108SDag-Erling Smørgrav session_dump(); 2068d4ecd108SDag-Erling Smørgrav return NULL; 2069d4ecd108SDag-Erling Smørgrav } 2070d4ecd108SDag-Erling Smørgrav 2071d4ecd108SDag-Erling Smørgrav static Session * 2072a04a10f8SKris Kennaway session_by_pid(pid_t pid) 2073a04a10f8SKris Kennaway { 2074a04a10f8SKris Kennaway int i; 207580628bacSDag-Erling Smørgrav debug("session_by_pid: pid %ld", (long)pid); 2076d4af9e69SDag-Erling Smørgrav for (i = 0; i < sessions_nalloc; i++) { 2077a04a10f8SKris Kennaway Session *s = &sessions[i]; 2078a04a10f8SKris Kennaway if (s->used && s->pid == pid) 2079a04a10f8SKris Kennaway return s; 2080a04a10f8SKris Kennaway } 208180628bacSDag-Erling Smørgrav error("session_by_pid: unknown pid %ld", (long)pid); 2082a04a10f8SKris Kennaway session_dump(); 2083a04a10f8SKris Kennaway return NULL; 2084a04a10f8SKris Kennaway } 2085a04a10f8SKris Kennaway 2086af12a3e7SDag-Erling Smørgrav static int 2087a04a10f8SKris Kennaway session_window_change_req(Session *s) 2088a04a10f8SKris Kennaway { 2089a04a10f8SKris Kennaway s->col = packet_get_int(); 2090a04a10f8SKris Kennaway s->row = packet_get_int(); 2091a04a10f8SKris Kennaway s->xpixel = packet_get_int(); 2092a04a10f8SKris Kennaway s->ypixel = packet_get_int(); 2093af12a3e7SDag-Erling Smørgrav packet_check_eom(); 2094a04a10f8SKris Kennaway pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); 2095a04a10f8SKris Kennaway return 1; 2096a04a10f8SKris Kennaway } 2097a04a10f8SKris Kennaway 2098af12a3e7SDag-Erling Smørgrav static int 2099a04a10f8SKris Kennaway session_pty_req(Session *s) 2100a04a10f8SKris Kennaway { 2101ca3176e7SBrian Feldman u_int len; 2102ca3176e7SBrian Feldman int n_bytes; 2103a04a10f8SKris Kennaway 2104af12a3e7SDag-Erling Smørgrav if (no_pty_flag) { 2105af12a3e7SDag-Erling Smørgrav debug("Allocating a pty not permitted for this authentication."); 2106c2d3a559SKris Kennaway return 0; 2107af12a3e7SDag-Erling Smørgrav } 2108af12a3e7SDag-Erling Smørgrav if (s->ttyfd != -1) { 2109af12a3e7SDag-Erling Smørgrav packet_disconnect("Protocol error: you already have a pty."); 2110a04a10f8SKris Kennaway return 0; 2111af12a3e7SDag-Erling Smørgrav } 2112af12a3e7SDag-Erling Smørgrav 2113a04a10f8SKris Kennaway s->term = packet_get_string(&len); 2114af12a3e7SDag-Erling Smørgrav 2115af12a3e7SDag-Erling Smørgrav if (compat20) { 2116a04a10f8SKris Kennaway s->col = packet_get_int(); 2117a04a10f8SKris Kennaway s->row = packet_get_int(); 2118af12a3e7SDag-Erling Smørgrav } else { 2119af12a3e7SDag-Erling Smørgrav s->row = packet_get_int(); 2120af12a3e7SDag-Erling Smørgrav s->col = packet_get_int(); 2121af12a3e7SDag-Erling Smørgrav } 2122a04a10f8SKris Kennaway s->xpixel = packet_get_int(); 2123a04a10f8SKris Kennaway s->ypixel = packet_get_int(); 2124a04a10f8SKris Kennaway 2125a04a10f8SKris Kennaway if (strcmp(s->term, "") == 0) { 2126a04a10f8SKris Kennaway xfree(s->term); 2127a04a10f8SKris Kennaway s->term = NULL; 2128a04a10f8SKris Kennaway } 2129af12a3e7SDag-Erling Smørgrav 2130a04a10f8SKris Kennaway /* Allocate a pty and open it. */ 2131af12a3e7SDag-Erling Smørgrav debug("Allocating pty."); 2132d4af9e69SDag-Erling Smørgrav if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, 2133d4af9e69SDag-Erling Smørgrav sizeof(s->tty)))) { 2134af12a3e7SDag-Erling Smørgrav if (s->term) 2135a04a10f8SKris Kennaway xfree(s->term); 2136a04a10f8SKris Kennaway s->term = NULL; 2137a04a10f8SKris Kennaway s->ptyfd = -1; 2138a04a10f8SKris Kennaway s->ttyfd = -1; 2139a04a10f8SKris Kennaway error("session_pty_req: session %d alloc failed", s->self); 2140a04a10f8SKris Kennaway return 0; 2141a04a10f8SKris Kennaway } 2142a04a10f8SKris Kennaway debug("session_pty_req: session %d alloc %s", s->self, s->tty); 2143af12a3e7SDag-Erling Smørgrav 2144af12a3e7SDag-Erling Smørgrav /* for SSH1 the tty modes length is not given */ 2145af12a3e7SDag-Erling Smørgrav if (!compat20) 2146af12a3e7SDag-Erling Smørgrav n_bytes = packet_remaining(); 2147af12a3e7SDag-Erling Smørgrav tty_parse_modes(s->ttyfd, &n_bytes); 2148af12a3e7SDag-Erling Smørgrav 214980628bacSDag-Erling Smørgrav if (!use_privsep) 2150a04a10f8SKris Kennaway pty_setowner(s->pw, s->tty); 2151af12a3e7SDag-Erling Smørgrav 2152af12a3e7SDag-Erling Smørgrav /* Set window size from the packet. */ 2153a04a10f8SKris Kennaway pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); 2154a04a10f8SKris Kennaway 2155af12a3e7SDag-Erling Smørgrav packet_check_eom(); 2156a04a10f8SKris Kennaway session_proctitle(s); 2157a04a10f8SKris Kennaway return 1; 2158a04a10f8SKris Kennaway } 2159a04a10f8SKris Kennaway 2160af12a3e7SDag-Erling Smørgrav static int 2161a04a10f8SKris Kennaway session_subsystem_req(Session *s) 2162a04a10f8SKris Kennaway { 2163af12a3e7SDag-Erling Smørgrav struct stat st; 2164ca3176e7SBrian Feldman u_int len; 2165a04a10f8SKris Kennaway int success = 0; 2166333ee039SDag-Erling Smørgrav char *prog, *cmd, *subsys = packet_get_string(&len); 2167d4ecd108SDag-Erling Smørgrav u_int i; 2168a04a10f8SKris Kennaway 2169af12a3e7SDag-Erling Smørgrav packet_check_eom(); 2170cf2b5f3bSDag-Erling Smørgrav logit("subsystem request for %.100s", subsys); 2171a04a10f8SKris Kennaway 2172c2d3a559SKris Kennaway for (i = 0; i < options.num_subsystems; i++) { 2173c2d3a559SKris Kennaway if (strcmp(subsys, options.subsystem_name[i]) == 0) { 2174333ee039SDag-Erling Smørgrav prog = options.subsystem_command[i]; 2175333ee039SDag-Erling Smørgrav cmd = options.subsystem_args[i]; 2176b15c8340SDag-Erling Smørgrav if (strcmp(INTERNAL_SFTP_NAME, prog) == 0) { 2177d4af9e69SDag-Erling Smørgrav s->is_subsystem = SUBSYSTEM_INT_SFTP; 2178b15c8340SDag-Erling Smørgrav debug("subsystem: %s", prog); 2179d4af9e69SDag-Erling Smørgrav } else { 2180b15c8340SDag-Erling Smørgrav if (stat(prog, &st) < 0) 2181b15c8340SDag-Erling Smørgrav debug("subsystem: cannot stat %s: %s", 2182b15c8340SDag-Erling Smørgrav prog, strerror(errno)); 2183d4af9e69SDag-Erling Smørgrav s->is_subsystem = SUBSYSTEM_EXT; 2184af12a3e7SDag-Erling Smørgrav debug("subsystem: exec() %s", cmd); 2185b15c8340SDag-Erling Smørgrav } 2186d4af9e69SDag-Erling Smørgrav success = do_exec(s, cmd) == 0; 2187af12a3e7SDag-Erling Smørgrav break; 2188c2d3a559SKris Kennaway } 2189c2d3a559SKris Kennaway } 2190c2d3a559SKris Kennaway 2191c2d3a559SKris Kennaway if (!success) 2192cf2b5f3bSDag-Erling Smørgrav logit("subsystem request for %.100s failed, subsystem not found", 2193af12a3e7SDag-Erling Smørgrav subsys); 2194c2d3a559SKris Kennaway 2195a04a10f8SKris Kennaway xfree(subsys); 2196a04a10f8SKris Kennaway return success; 2197a04a10f8SKris Kennaway } 2198a04a10f8SKris Kennaway 2199af12a3e7SDag-Erling Smørgrav static int 2200a04a10f8SKris Kennaway session_x11_req(Session *s) 2201a04a10f8SKris Kennaway { 2202af12a3e7SDag-Erling Smørgrav int success; 2203a04a10f8SKris Kennaway 2204d4ecd108SDag-Erling Smørgrav if (s->auth_proto != NULL || s->auth_data != NULL) { 2205d4ecd108SDag-Erling Smørgrav error("session_x11_req: session %d: " 2206b74df5b2SDag-Erling Smørgrav "x11 forwarding already active", s->self); 2207d4ecd108SDag-Erling Smørgrav return 0; 2208d4ecd108SDag-Erling Smørgrav } 2209a04a10f8SKris Kennaway s->single_connection = packet_get_char(); 2210a04a10f8SKris Kennaway s->auth_proto = packet_get_string(NULL); 2211a04a10f8SKris Kennaway s->auth_data = packet_get_string(NULL); 2212a04a10f8SKris Kennaway s->screen = packet_get_int(); 2213af12a3e7SDag-Erling Smørgrav packet_check_eom(); 2214a04a10f8SKris Kennaway 2215af12a3e7SDag-Erling Smørgrav success = session_setup_x11fwd(s); 2216af12a3e7SDag-Erling Smørgrav if (!success) { 2217a04a10f8SKris Kennaway xfree(s->auth_proto); 2218a04a10f8SKris Kennaway xfree(s->auth_data); 2219af12a3e7SDag-Erling Smørgrav s->auth_proto = NULL; 2220af12a3e7SDag-Erling Smørgrav s->auth_data = NULL; 2221a04a10f8SKris Kennaway } 2222af12a3e7SDag-Erling Smørgrav return success; 2223a04a10f8SKris Kennaway } 2224a04a10f8SKris Kennaway 2225af12a3e7SDag-Erling Smørgrav static int 2226c2d3a559SKris Kennaway session_shell_req(Session *s) 2227c2d3a559SKris Kennaway { 2228af12a3e7SDag-Erling Smørgrav packet_check_eom(); 2229d4af9e69SDag-Erling Smørgrav return do_exec(s, NULL) == 0; 2230c2d3a559SKris Kennaway } 2231c2d3a559SKris Kennaway 2232af12a3e7SDag-Erling Smørgrav static int 2233c2d3a559SKris Kennaway session_exec_req(Session *s) 2234c2d3a559SKris Kennaway { 2235d4af9e69SDag-Erling Smørgrav u_int len, success; 2236d4af9e69SDag-Erling Smørgrav 2237c2d3a559SKris Kennaway char *command = packet_get_string(&len); 2238af12a3e7SDag-Erling Smørgrav packet_check_eom(); 2239d4af9e69SDag-Erling Smørgrav success = do_exec(s, command) == 0; 2240c2d3a559SKris Kennaway xfree(command); 2241d4af9e69SDag-Erling Smørgrav return success; 2242c2d3a559SKris Kennaway } 2243c2d3a559SKris Kennaway 2244af12a3e7SDag-Erling Smørgrav static int 2245cf2b5f3bSDag-Erling Smørgrav session_break_req(Session *s) 2246cf2b5f3bSDag-Erling Smørgrav { 2247cf2b5f3bSDag-Erling Smørgrav 224821e764dfSDag-Erling Smørgrav packet_get_int(); /* ignored */ 2249cf2b5f3bSDag-Erling Smørgrav packet_check_eom(); 2250cf2b5f3bSDag-Erling Smørgrav 2251d4af9e69SDag-Erling Smørgrav if (s->ttyfd == -1 || tcsendbreak(s->ttyfd, 0) < 0) 2252cf2b5f3bSDag-Erling Smørgrav return 0; 2253cf2b5f3bSDag-Erling Smørgrav return 1; 2254cf2b5f3bSDag-Erling Smørgrav } 2255cf2b5f3bSDag-Erling Smørgrav 2256cf2b5f3bSDag-Erling Smørgrav static int 225721e764dfSDag-Erling Smørgrav session_env_req(Session *s) 225821e764dfSDag-Erling Smørgrav { 225921e764dfSDag-Erling Smørgrav char *name, *val; 226021e764dfSDag-Erling Smørgrav u_int name_len, val_len, i; 226121e764dfSDag-Erling Smørgrav 226221e764dfSDag-Erling Smørgrav name = packet_get_string(&name_len); 226321e764dfSDag-Erling Smørgrav val = packet_get_string(&val_len); 226421e764dfSDag-Erling Smørgrav packet_check_eom(); 226521e764dfSDag-Erling Smørgrav 226621e764dfSDag-Erling Smørgrav /* Don't set too many environment variables */ 226721e764dfSDag-Erling Smørgrav if (s->num_env > 128) { 226821e764dfSDag-Erling Smørgrav debug2("Ignoring env request %s: too many env vars", name); 226921e764dfSDag-Erling Smørgrav goto fail; 227021e764dfSDag-Erling Smørgrav } 227121e764dfSDag-Erling Smørgrav 227221e764dfSDag-Erling Smørgrav for (i = 0; i < options.num_accept_env; i++) { 227321e764dfSDag-Erling Smørgrav if (match_pattern(name, options.accept_env[i])) { 227421e764dfSDag-Erling Smørgrav debug2("Setting env %d: %s=%s", s->num_env, name, val); 2275333ee039SDag-Erling Smørgrav s->env = xrealloc(s->env, s->num_env + 1, 2276333ee039SDag-Erling Smørgrav sizeof(*s->env)); 227721e764dfSDag-Erling Smørgrav s->env[s->num_env].name = name; 227821e764dfSDag-Erling Smørgrav s->env[s->num_env].val = val; 227921e764dfSDag-Erling Smørgrav s->num_env++; 228021e764dfSDag-Erling Smørgrav return (1); 228121e764dfSDag-Erling Smørgrav } 228221e764dfSDag-Erling Smørgrav } 228321e764dfSDag-Erling Smørgrav debug2("Ignoring env request %s: disallowed name", name); 228421e764dfSDag-Erling Smørgrav 228521e764dfSDag-Erling Smørgrav fail: 228621e764dfSDag-Erling Smørgrav xfree(name); 228721e764dfSDag-Erling Smørgrav xfree(val); 228821e764dfSDag-Erling Smørgrav return (0); 228921e764dfSDag-Erling Smørgrav } 229021e764dfSDag-Erling Smørgrav 229121e764dfSDag-Erling Smørgrav static int 2292ca3176e7SBrian Feldman session_auth_agent_req(Session *s) 2293ca3176e7SBrian Feldman { 2294ca3176e7SBrian Feldman static int called = 0; 2295af12a3e7SDag-Erling Smørgrav packet_check_eom(); 2296d4af9e69SDag-Erling Smørgrav if (no_agent_forwarding_flag || !options.allow_agent_forwarding) { 2297ca3176e7SBrian Feldman debug("session_auth_agent_req: no_agent_forwarding_flag"); 2298ca3176e7SBrian Feldman return 0; 2299ca3176e7SBrian Feldman } 2300ca3176e7SBrian Feldman if (called) { 2301ca3176e7SBrian Feldman return 0; 2302ca3176e7SBrian Feldman } else { 2303ca3176e7SBrian Feldman called = 1; 2304ca3176e7SBrian Feldman return auth_input_request_forwarding(s->pw); 2305ca3176e7SBrian Feldman } 2306ca3176e7SBrian Feldman } 2307ca3176e7SBrian Feldman 2308af12a3e7SDag-Erling Smørgrav int 2309af12a3e7SDag-Erling Smørgrav session_input_channel_req(Channel *c, const char *rtype) 2310a04a10f8SKris Kennaway { 2311a04a10f8SKris Kennaway int success = 0; 2312a04a10f8SKris Kennaway Session *s; 2313a04a10f8SKris Kennaway 2314af12a3e7SDag-Erling Smørgrav if ((s = session_by_channel(c->self)) == NULL) { 2315cf2b5f3bSDag-Erling Smørgrav logit("session_input_channel_req: no session %d req %.100s", 2316af12a3e7SDag-Erling Smørgrav c->self, rtype); 2317af12a3e7SDag-Erling Smørgrav return 0; 2318af12a3e7SDag-Erling Smørgrav } 2319af12a3e7SDag-Erling Smørgrav debug("session_input_channel_req: session %d req %s", s->self, rtype); 2320a04a10f8SKris Kennaway 2321a04a10f8SKris Kennaway /* 2322ca3176e7SBrian Feldman * a session is in LARVAL state until a shell, a command 2323ca3176e7SBrian Feldman * or a subsystem is executed 2324a04a10f8SKris Kennaway */ 2325a04a10f8SKris Kennaway if (c->type == SSH_CHANNEL_LARVAL) { 2326a04a10f8SKris Kennaway if (strcmp(rtype, "shell") == 0) { 2327c2d3a559SKris Kennaway success = session_shell_req(s); 2328a04a10f8SKris Kennaway } else if (strcmp(rtype, "exec") == 0) { 2329c2d3a559SKris Kennaway success = session_exec_req(s); 2330a04a10f8SKris Kennaway } else if (strcmp(rtype, "pty-req") == 0) { 2331a04a10f8SKris Kennaway success = session_pty_req(s); 2332a04a10f8SKris Kennaway } else if (strcmp(rtype, "x11-req") == 0) { 2333a04a10f8SKris Kennaway success = session_x11_req(s); 2334ca3176e7SBrian Feldman } else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) { 2335ca3176e7SBrian Feldman success = session_auth_agent_req(s); 2336a04a10f8SKris Kennaway } else if (strcmp(rtype, "subsystem") == 0) { 2337a04a10f8SKris Kennaway success = session_subsystem_req(s); 233821e764dfSDag-Erling Smørgrav } else if (strcmp(rtype, "env") == 0) { 233921e764dfSDag-Erling Smørgrav success = session_env_req(s); 2340a04a10f8SKris Kennaway } 2341a04a10f8SKris Kennaway } 2342a04a10f8SKris Kennaway if (strcmp(rtype, "window-change") == 0) { 2343a04a10f8SKris Kennaway success = session_window_change_req(s); 234421e764dfSDag-Erling Smørgrav } else if (strcmp(rtype, "break") == 0) { 234521e764dfSDag-Erling Smørgrav success = session_break_req(s); 2346a04a10f8SKris Kennaway } 234721e764dfSDag-Erling Smørgrav 2348af12a3e7SDag-Erling Smørgrav return success; 2349a04a10f8SKris Kennaway } 2350a04a10f8SKris Kennaway 2351a04a10f8SKris Kennaway void 2352d4af9e69SDag-Erling Smørgrav session_set_fds(Session *s, int fdin, int fdout, int fderr, int is_tty) 2353a04a10f8SKris Kennaway { 2354a04a10f8SKris Kennaway if (!compat20) 2355a04a10f8SKris Kennaway fatal("session_set_fds: called for proto != 2.0"); 2356a04a10f8SKris Kennaway /* 2357a04a10f8SKris Kennaway * now that have a child and a pipe to the child, 2358a04a10f8SKris Kennaway * we can activate our channel and register the fd's 2359a04a10f8SKris Kennaway */ 2360a04a10f8SKris Kennaway if (s->chanid == -1) 2361a04a10f8SKris Kennaway fatal("no channel for session %d", s->self); 2362a04a10f8SKris Kennaway channel_set_fds(s->chanid, 2363a04a10f8SKris Kennaway fdout, fdin, fderr, 236409958426SBrian Feldman fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, 2365d4af9e69SDag-Erling Smørgrav 1, is_tty, CHAN_SES_WINDOW_DEFAULT); 2366a04a10f8SKris Kennaway } 2367a04a10f8SKris Kennaway 2368af12a3e7SDag-Erling Smørgrav /* 2369af12a3e7SDag-Erling Smørgrav * Function to perform pty cleanup. Also called if we get aborted abnormally 2370af12a3e7SDag-Erling Smørgrav * (e.g., due to a dropped connection). 2371af12a3e7SDag-Erling Smørgrav */ 237280628bacSDag-Erling Smørgrav void 23731ec0d754SDag-Erling Smørgrav session_pty_cleanup2(Session *s) 2374a04a10f8SKris Kennaway { 2375af12a3e7SDag-Erling Smørgrav if (s == NULL) { 2376af12a3e7SDag-Erling Smørgrav error("session_pty_cleanup: no session"); 2377af12a3e7SDag-Erling Smørgrav return; 2378af12a3e7SDag-Erling Smørgrav } 2379af12a3e7SDag-Erling Smørgrav if (s->ttyfd == -1) 2380a04a10f8SKris Kennaway return; 2381a04a10f8SKris Kennaway 2382ca3176e7SBrian Feldman debug("session_pty_cleanup: session %d release %s", s->self, s->tty); 2383a04a10f8SKris Kennaway 2384a04a10f8SKris Kennaway /* Record that the user has logged out. */ 2385af12a3e7SDag-Erling Smørgrav if (s->pid != 0) 2386989dd127SDag-Erling Smørgrav record_logout(s->pid, s->tty, s->pw->pw_name); 2387a04a10f8SKris Kennaway 2388a04a10f8SKris Kennaway /* Release the pseudo-tty. */ 238980628bacSDag-Erling Smørgrav if (getuid() == 0) 2390a04a10f8SKris Kennaway pty_release(s->tty); 2391a04a10f8SKris Kennaway 2392a04a10f8SKris Kennaway /* 2393a04a10f8SKris Kennaway * Close the server side of the socket pairs. We must do this after 2394a04a10f8SKris Kennaway * the pty cleanup, so that another process doesn't get this pty 2395a04a10f8SKris Kennaway * while we're still cleaning up. 2396a04a10f8SKris Kennaway */ 2397d4af9e69SDag-Erling Smørgrav if (s->ptymaster != -1 && close(s->ptymaster) < 0) 2398d4af9e69SDag-Erling Smørgrav error("close(s->ptymaster/%d): %s", 2399d4af9e69SDag-Erling Smørgrav s->ptymaster, strerror(errno)); 2400af12a3e7SDag-Erling Smørgrav 2401af12a3e7SDag-Erling Smørgrav /* unlink pty from session */ 2402af12a3e7SDag-Erling Smørgrav s->ttyfd = -1; 2403a04a10f8SKris Kennaway } 2404a04a10f8SKris Kennaway 240580628bacSDag-Erling Smørgrav void 24061ec0d754SDag-Erling Smørgrav session_pty_cleanup(Session *s) 240780628bacSDag-Erling Smørgrav { 24081ec0d754SDag-Erling Smørgrav PRIVSEP(session_pty_cleanup2(s)); 240980628bacSDag-Erling Smørgrav } 241080628bacSDag-Erling Smørgrav 2411f388f5efSDag-Erling Smørgrav static char * 2412f388f5efSDag-Erling Smørgrav sig2name(int sig) 2413f388f5efSDag-Erling Smørgrav { 2414f388f5efSDag-Erling Smørgrav #define SSH_SIG(x) if (sig == SIG ## x) return #x 2415f388f5efSDag-Erling Smørgrav SSH_SIG(ABRT); 2416f388f5efSDag-Erling Smørgrav SSH_SIG(ALRM); 2417f388f5efSDag-Erling Smørgrav SSH_SIG(FPE); 2418f388f5efSDag-Erling Smørgrav SSH_SIG(HUP); 2419f388f5efSDag-Erling Smørgrav SSH_SIG(ILL); 2420f388f5efSDag-Erling Smørgrav SSH_SIG(INT); 2421f388f5efSDag-Erling Smørgrav SSH_SIG(KILL); 2422f388f5efSDag-Erling Smørgrav SSH_SIG(PIPE); 2423f388f5efSDag-Erling Smørgrav SSH_SIG(QUIT); 2424f388f5efSDag-Erling Smørgrav SSH_SIG(SEGV); 2425f388f5efSDag-Erling Smørgrav SSH_SIG(TERM); 2426f388f5efSDag-Erling Smørgrav SSH_SIG(USR1); 2427f388f5efSDag-Erling Smørgrav SSH_SIG(USR2); 2428f388f5efSDag-Erling Smørgrav #undef SSH_SIG 2429f388f5efSDag-Erling Smørgrav return "SIG@openssh.com"; 2430f388f5efSDag-Erling Smørgrav } 2431f388f5efSDag-Erling Smørgrav 2432af12a3e7SDag-Erling Smørgrav static void 2433d4ecd108SDag-Erling Smørgrav session_close_x11(int id) 2434d4ecd108SDag-Erling Smørgrav { 2435d4ecd108SDag-Erling Smørgrav Channel *c; 2436d4ecd108SDag-Erling Smørgrav 2437b74df5b2SDag-Erling Smørgrav if ((c = channel_by_id(id)) == NULL) { 2438d4ecd108SDag-Erling Smørgrav debug("session_close_x11: x11 channel %d missing", id); 2439d4ecd108SDag-Erling Smørgrav } else { 2440d4ecd108SDag-Erling Smørgrav /* Detach X11 listener */ 2441d4ecd108SDag-Erling Smørgrav debug("session_close_x11: detach x11 channel %d", id); 2442d4ecd108SDag-Erling Smørgrav channel_cancel_cleanup(id); 2443d4ecd108SDag-Erling Smørgrav if (c->ostate != CHAN_OUTPUT_CLOSED) 2444d4ecd108SDag-Erling Smørgrav chan_mark_dead(c); 2445d4ecd108SDag-Erling Smørgrav } 2446d4ecd108SDag-Erling Smørgrav } 2447d4ecd108SDag-Erling Smørgrav 2448d4ecd108SDag-Erling Smørgrav static void 2449d4ecd108SDag-Erling Smørgrav session_close_single_x11(int id, void *arg) 2450d4ecd108SDag-Erling Smørgrav { 2451d4ecd108SDag-Erling Smørgrav Session *s; 2452d4ecd108SDag-Erling Smørgrav u_int i; 2453d4ecd108SDag-Erling Smørgrav 2454d4ecd108SDag-Erling Smørgrav debug3("session_close_single_x11: channel %d", id); 2455d4ecd108SDag-Erling Smørgrav channel_cancel_cleanup(id); 2456d4ecd108SDag-Erling Smørgrav if ((s = session_by_x11_channel(id)) == NULL) 2457d4ecd108SDag-Erling Smørgrav fatal("session_close_single_x11: no x11 channel %d", id); 2458d4ecd108SDag-Erling Smørgrav for (i = 0; s->x11_chanids[i] != -1; i++) { 2459d4ecd108SDag-Erling Smørgrav debug("session_close_single_x11: session %d: " 2460d4ecd108SDag-Erling Smørgrav "closing channel %d", s->self, s->x11_chanids[i]); 2461d4ecd108SDag-Erling Smørgrav /* 2462d4ecd108SDag-Erling Smørgrav * The channel "id" is already closing, but make sure we 2463d4ecd108SDag-Erling Smørgrav * close all of its siblings. 2464d4ecd108SDag-Erling Smørgrav */ 2465d4ecd108SDag-Erling Smørgrav if (s->x11_chanids[i] != id) 2466d4ecd108SDag-Erling Smørgrav session_close_x11(s->x11_chanids[i]); 2467d4ecd108SDag-Erling Smørgrav } 2468d4ecd108SDag-Erling Smørgrav xfree(s->x11_chanids); 2469d4ecd108SDag-Erling Smørgrav s->x11_chanids = NULL; 2470d4ecd108SDag-Erling Smørgrav if (s->display) { 2471d4ecd108SDag-Erling Smørgrav xfree(s->display); 2472d4ecd108SDag-Erling Smørgrav s->display = NULL; 2473d4ecd108SDag-Erling Smørgrav } 2474d4ecd108SDag-Erling Smørgrav if (s->auth_proto) { 2475d4ecd108SDag-Erling Smørgrav xfree(s->auth_proto); 2476d4ecd108SDag-Erling Smørgrav s->auth_proto = NULL; 2477d4ecd108SDag-Erling Smørgrav } 2478d4ecd108SDag-Erling Smørgrav if (s->auth_data) { 2479d4ecd108SDag-Erling Smørgrav xfree(s->auth_data); 2480d4ecd108SDag-Erling Smørgrav s->auth_data = NULL; 2481d4ecd108SDag-Erling Smørgrav } 2482d4ecd108SDag-Erling Smørgrav if (s->auth_display) { 2483d4ecd108SDag-Erling Smørgrav xfree(s->auth_display); 2484d4ecd108SDag-Erling Smørgrav s->auth_display = NULL; 2485d4ecd108SDag-Erling Smørgrav } 2486d4ecd108SDag-Erling Smørgrav } 2487d4ecd108SDag-Erling Smørgrav 2488d4ecd108SDag-Erling Smørgrav static void 2489a04a10f8SKris Kennaway session_exit_message(Session *s, int status) 2490a04a10f8SKris Kennaway { 2491a04a10f8SKris Kennaway Channel *c; 2492af12a3e7SDag-Erling Smørgrav 2493af12a3e7SDag-Erling Smørgrav if ((c = channel_lookup(s->chanid)) == NULL) 2494af12a3e7SDag-Erling Smørgrav fatal("session_exit_message: session %d: no channel %d", 2495a04a10f8SKris Kennaway s->self, s->chanid); 249680628bacSDag-Erling Smørgrav debug("session_exit_message: session %d channel %d pid %ld", 249780628bacSDag-Erling Smørgrav s->self, s->chanid, (long)s->pid); 2498a04a10f8SKris Kennaway 2499a04a10f8SKris Kennaway if (WIFEXITED(status)) { 2500af12a3e7SDag-Erling Smørgrav channel_request_start(s->chanid, "exit-status", 0); 2501a04a10f8SKris Kennaway packet_put_int(WEXITSTATUS(status)); 2502a04a10f8SKris Kennaway packet_send(); 2503a04a10f8SKris Kennaway } else if (WIFSIGNALED(status)) { 2504af12a3e7SDag-Erling Smørgrav channel_request_start(s->chanid, "exit-signal", 0); 2505f388f5efSDag-Erling Smørgrav packet_put_cstring(sig2name(WTERMSIG(status))); 2506989dd127SDag-Erling Smørgrav #ifdef WCOREDUMP 2507d4af9e69SDag-Erling Smørgrav packet_put_char(WCOREDUMP(status)? 1 : 0); 2508989dd127SDag-Erling Smørgrav #else /* WCOREDUMP */ 2509989dd127SDag-Erling Smørgrav packet_put_char(0); 2510989dd127SDag-Erling Smørgrav #endif /* WCOREDUMP */ 2511a04a10f8SKris Kennaway packet_put_cstring(""); 2512a04a10f8SKris Kennaway packet_put_cstring(""); 2513a04a10f8SKris Kennaway packet_send(); 2514a04a10f8SKris Kennaway } else { 2515a04a10f8SKris Kennaway /* Some weird exit cause. Just exit. */ 2516a04a10f8SKris Kennaway packet_disconnect("wait returned status %04x.", status); 2517a04a10f8SKris Kennaway } 2518a04a10f8SKris Kennaway 2519a04a10f8SKris Kennaway /* disconnect channel */ 2520a04a10f8SKris Kennaway debug("session_exit_message: release channel %d", s->chanid); 2521b74df5b2SDag-Erling Smørgrav 2522b74df5b2SDag-Erling Smørgrav /* 2523b74df5b2SDag-Erling Smørgrav * Adjust cleanup callback attachment to send close messages when 2524b74df5b2SDag-Erling Smørgrav * the channel gets EOF. The session will be then be closed 2525b74df5b2SDag-Erling Smørgrav * by session_close_by_channel when the childs close their fds. 2526b74df5b2SDag-Erling Smørgrav */ 2527b74df5b2SDag-Erling Smørgrav channel_register_cleanup(c->self, session_close_by_channel, 1); 2528b74df5b2SDag-Erling Smørgrav 2529a04a10f8SKris Kennaway /* 2530a04a10f8SKris Kennaway * emulate a write failure with 'chan_write_failed', nobody will be 2531a04a10f8SKris Kennaway * interested in data we write. 2532a04a10f8SKris Kennaway * Note that we must not call 'chan_read_failed', since there could 2533a04a10f8SKris Kennaway * be some more data waiting in the pipe. 2534a04a10f8SKris Kennaway */ 2535a04a10f8SKris Kennaway if (c->ostate != CHAN_OUTPUT_CLOSED) 2536a04a10f8SKris Kennaway chan_write_failed(c); 2537a04a10f8SKris Kennaway } 2538a04a10f8SKris Kennaway 253980628bacSDag-Erling Smørgrav void 2540af12a3e7SDag-Erling Smørgrav session_close(Session *s) 2541a04a10f8SKris Kennaway { 2542d4ecd108SDag-Erling Smørgrav u_int i; 254321e764dfSDag-Erling Smørgrav 254480628bacSDag-Erling Smørgrav debug("session_close: session %d pid %ld", s->self, (long)s->pid); 25451ec0d754SDag-Erling Smørgrav if (s->ttyfd != -1) 2546af12a3e7SDag-Erling Smørgrav session_pty_cleanup(s); 2547a04a10f8SKris Kennaway if (s->term) 2548a04a10f8SKris Kennaway xfree(s->term); 2549a04a10f8SKris Kennaway if (s->display) 2550a04a10f8SKris Kennaway xfree(s->display); 2551d4ecd108SDag-Erling Smørgrav if (s->x11_chanids) 2552d4ecd108SDag-Erling Smørgrav xfree(s->x11_chanids); 2553af12a3e7SDag-Erling Smørgrav if (s->auth_display) 2554af12a3e7SDag-Erling Smørgrav xfree(s->auth_display); 2555a04a10f8SKris Kennaway if (s->auth_data) 2556a04a10f8SKris Kennaway xfree(s->auth_data); 2557a04a10f8SKris Kennaway if (s->auth_proto) 2558a04a10f8SKris Kennaway xfree(s->auth_proto); 2559333ee039SDag-Erling Smørgrav if (s->env != NULL) { 256021e764dfSDag-Erling Smørgrav for (i = 0; i < s->num_env; i++) { 256121e764dfSDag-Erling Smørgrav xfree(s->env[i].name); 256221e764dfSDag-Erling Smørgrav xfree(s->env[i].val); 256321e764dfSDag-Erling Smørgrav } 256421e764dfSDag-Erling Smørgrav xfree(s->env); 2565333ee039SDag-Erling Smørgrav } 2566a04a10f8SKris Kennaway session_proctitle(s); 2567d4af9e69SDag-Erling Smørgrav session_unused(s->self); 2568a04a10f8SKris Kennaway } 2569a04a10f8SKris Kennaway 2570a04a10f8SKris Kennaway void 2571a04a10f8SKris Kennaway session_close_by_pid(pid_t pid, int status) 2572a04a10f8SKris Kennaway { 2573a04a10f8SKris Kennaway Session *s = session_by_pid(pid); 2574a04a10f8SKris Kennaway if (s == NULL) { 257580628bacSDag-Erling Smørgrav debug("session_close_by_pid: no session for pid %ld", 257680628bacSDag-Erling Smørgrav (long)pid); 2577a04a10f8SKris Kennaway return; 2578a04a10f8SKris Kennaway } 2579a04a10f8SKris Kennaway if (s->chanid != -1) 2580a04a10f8SKris Kennaway session_exit_message(s, status); 2581b74df5b2SDag-Erling Smørgrav if (s->ttyfd != -1) 2582b74df5b2SDag-Erling Smørgrav session_pty_cleanup(s); 2583333ee039SDag-Erling Smørgrav s->pid = 0; 2584a04a10f8SKris Kennaway } 2585a04a10f8SKris Kennaway 2586a04a10f8SKris Kennaway /* 2587a04a10f8SKris Kennaway * this is called when a channel dies before 2588a04a10f8SKris Kennaway * the session 'child' itself dies 2589a04a10f8SKris Kennaway */ 2590a04a10f8SKris Kennaway void 2591a04a10f8SKris Kennaway session_close_by_channel(int id, void *arg) 2592a04a10f8SKris Kennaway { 2593a04a10f8SKris Kennaway Session *s = session_by_channel(id); 2594b74df5b2SDag-Erling Smørgrav u_int i; 2595d4ecd108SDag-Erling Smørgrav 2596a04a10f8SKris Kennaway if (s == NULL) { 2597af12a3e7SDag-Erling Smørgrav debug("session_close_by_channel: no session for id %d", id); 2598a04a10f8SKris Kennaway return; 2599a04a10f8SKris Kennaway } 260080628bacSDag-Erling Smørgrav debug("session_close_by_channel: channel %d child %ld", 260180628bacSDag-Erling Smørgrav id, (long)s->pid); 2602af12a3e7SDag-Erling Smørgrav if (s->pid != 0) { 2603af12a3e7SDag-Erling Smørgrav debug("session_close_by_channel: channel %d: has child", id); 2604af12a3e7SDag-Erling Smørgrav /* 2605af12a3e7SDag-Erling Smørgrav * delay detach of session, but release pty, since 2606af12a3e7SDag-Erling Smørgrav * the fd's to the child are already closed 2607af12a3e7SDag-Erling Smørgrav */ 26081ec0d754SDag-Erling Smørgrav if (s->ttyfd != -1) 2609af12a3e7SDag-Erling Smørgrav session_pty_cleanup(s); 2610af12a3e7SDag-Erling Smørgrav return; 2611af12a3e7SDag-Erling Smørgrav } 2612af12a3e7SDag-Erling Smørgrav /* detach by removing callback */ 2613a04a10f8SKris Kennaway channel_cancel_cleanup(s->chanid); 2614b74df5b2SDag-Erling Smørgrav 2615b74df5b2SDag-Erling Smørgrav /* Close any X11 listeners associated with this session */ 2616b74df5b2SDag-Erling Smørgrav if (s->x11_chanids != NULL) { 2617b74df5b2SDag-Erling Smørgrav for (i = 0; s->x11_chanids[i] != -1; i++) { 2618b74df5b2SDag-Erling Smørgrav session_close_x11(s->x11_chanids[i]); 2619b74df5b2SDag-Erling Smørgrav s->x11_chanids[i] = -1; 2620b74df5b2SDag-Erling Smørgrav } 2621b74df5b2SDag-Erling Smørgrav } 2622b74df5b2SDag-Erling Smørgrav 2623a04a10f8SKris Kennaway s->chanid = -1; 2624a04a10f8SKris Kennaway session_close(s); 2625af12a3e7SDag-Erling Smørgrav } 2626af12a3e7SDag-Erling Smørgrav 2627af12a3e7SDag-Erling Smørgrav void 262880628bacSDag-Erling Smørgrav session_destroy_all(void (*closefunc)(Session *)) 2629af12a3e7SDag-Erling Smørgrav { 2630af12a3e7SDag-Erling Smørgrav int i; 2631d4af9e69SDag-Erling Smørgrav for (i = 0; i < sessions_nalloc; i++) { 2632af12a3e7SDag-Erling Smørgrav Session *s = &sessions[i]; 263380628bacSDag-Erling Smørgrav if (s->used) { 263480628bacSDag-Erling Smørgrav if (closefunc != NULL) 263580628bacSDag-Erling Smørgrav closefunc(s); 263680628bacSDag-Erling Smørgrav else 2637af12a3e7SDag-Erling Smørgrav session_close(s); 2638a04a10f8SKris Kennaway } 2639a04a10f8SKris Kennaway } 264080628bacSDag-Erling Smørgrav } 2641a04a10f8SKris Kennaway 2642af12a3e7SDag-Erling Smørgrav static char * 2643a04a10f8SKris Kennaway session_tty_list(void) 2644a04a10f8SKris Kennaway { 2645a04a10f8SKris Kennaway static char buf[1024]; 2646a04a10f8SKris Kennaway int i; 2647e73e9afaSDag-Erling Smørgrav char *cp; 2648e73e9afaSDag-Erling Smørgrav 2649a04a10f8SKris Kennaway buf[0] = '\0'; 2650d4af9e69SDag-Erling Smørgrav for (i = 0; i < sessions_nalloc; i++) { 2651a04a10f8SKris Kennaway Session *s = &sessions[i]; 2652a04a10f8SKris Kennaway if (s->used && s->ttyfd != -1) { 2653e73e9afaSDag-Erling Smørgrav 2654e73e9afaSDag-Erling Smørgrav if (strncmp(s->tty, "/dev/", 5) != 0) { 2655e73e9afaSDag-Erling Smørgrav cp = strrchr(s->tty, '/'); 2656e73e9afaSDag-Erling Smørgrav cp = (cp == NULL) ? s->tty : cp + 1; 2657e73e9afaSDag-Erling Smørgrav } else 2658e73e9afaSDag-Erling Smørgrav cp = s->tty + 5; 2659e73e9afaSDag-Erling Smørgrav 2660a04a10f8SKris Kennaway if (buf[0] != '\0') 2661a04a10f8SKris Kennaway strlcat(buf, ",", sizeof buf); 2662e73e9afaSDag-Erling Smørgrav strlcat(buf, cp, sizeof buf); 2663a04a10f8SKris Kennaway } 2664a04a10f8SKris Kennaway } 2665a04a10f8SKris Kennaway if (buf[0] == '\0') 2666a04a10f8SKris Kennaway strlcpy(buf, "notty", sizeof buf); 2667a04a10f8SKris Kennaway return buf; 2668a04a10f8SKris Kennaway } 2669a04a10f8SKris Kennaway 2670a04a10f8SKris Kennaway void 2671a04a10f8SKris Kennaway session_proctitle(Session *s) 2672a04a10f8SKris Kennaway { 2673a04a10f8SKris Kennaway if (s->pw == NULL) 2674a04a10f8SKris Kennaway error("no user for session %d", s->self); 2675a04a10f8SKris Kennaway else 2676a04a10f8SKris Kennaway setproctitle("%s@%s", s->pw->pw_name, session_tty_list()); 2677a04a10f8SKris Kennaway } 2678a04a10f8SKris Kennaway 2679af12a3e7SDag-Erling Smørgrav int 2680af12a3e7SDag-Erling Smørgrav session_setup_x11fwd(Session *s) 2681af12a3e7SDag-Erling Smørgrav { 2682af12a3e7SDag-Erling Smørgrav struct stat st; 2683af12a3e7SDag-Erling Smørgrav char display[512], auth_display[512]; 2684af12a3e7SDag-Erling Smørgrav char hostname[MAXHOSTNAMELEN]; 2685d4ecd108SDag-Erling Smørgrav u_int i; 2686af12a3e7SDag-Erling Smørgrav 2687af12a3e7SDag-Erling Smørgrav if (no_x11_forwarding_flag) { 2688af12a3e7SDag-Erling Smørgrav packet_send_debug("X11 forwarding disabled in user configuration file."); 2689af12a3e7SDag-Erling Smørgrav return 0; 2690af12a3e7SDag-Erling Smørgrav } 2691af12a3e7SDag-Erling Smørgrav if (!options.x11_forwarding) { 2692af12a3e7SDag-Erling Smørgrav debug("X11 forwarding disabled in server configuration file."); 2693af12a3e7SDag-Erling Smørgrav return 0; 2694af12a3e7SDag-Erling Smørgrav } 2695af12a3e7SDag-Erling Smørgrav if (!options.xauth_location || 2696af12a3e7SDag-Erling Smørgrav (stat(options.xauth_location, &st) == -1)) { 2697af12a3e7SDag-Erling Smørgrav packet_send_debug("No xauth program; cannot forward with spoofing."); 2698af12a3e7SDag-Erling Smørgrav return 0; 2699af12a3e7SDag-Erling Smørgrav } 2700af12a3e7SDag-Erling Smørgrav if (options.use_login) { 2701af12a3e7SDag-Erling Smørgrav packet_send_debug("X11 forwarding disabled; " 2702af12a3e7SDag-Erling Smørgrav "not compatible with UseLogin=yes."); 2703af12a3e7SDag-Erling Smørgrav return 0; 2704af12a3e7SDag-Erling Smørgrav } 2705af12a3e7SDag-Erling Smørgrav if (s->display != NULL) { 2706af12a3e7SDag-Erling Smørgrav debug("X11 display already set."); 2707af12a3e7SDag-Erling Smørgrav return 0; 2708af12a3e7SDag-Erling Smørgrav } 2709a82e551fSDag-Erling Smørgrav if (x11_create_display_inet(options.x11_display_offset, 2710a82e551fSDag-Erling Smørgrav options.x11_use_localhost, s->single_connection, 2711d4ecd108SDag-Erling Smørgrav &s->display_number, &s->x11_chanids) == -1) { 2712af12a3e7SDag-Erling Smørgrav debug("x11_create_display_inet failed."); 2713af12a3e7SDag-Erling Smørgrav return 0; 2714af12a3e7SDag-Erling Smørgrav } 2715d4ecd108SDag-Erling Smørgrav for (i = 0; s->x11_chanids[i] != -1; i++) { 2716d4ecd108SDag-Erling Smørgrav channel_register_cleanup(s->x11_chanids[i], 2717b74df5b2SDag-Erling Smørgrav session_close_single_x11, 0); 2718d4ecd108SDag-Erling Smørgrav } 2719af12a3e7SDag-Erling Smørgrav 2720af12a3e7SDag-Erling Smørgrav /* Set up a suitable value for the DISPLAY variable. */ 2721af12a3e7SDag-Erling Smørgrav if (gethostname(hostname, sizeof(hostname)) < 0) 2722af12a3e7SDag-Erling Smørgrav fatal("gethostname: %.100s", strerror(errno)); 2723af12a3e7SDag-Erling Smørgrav /* 2724af12a3e7SDag-Erling Smørgrav * auth_display must be used as the displayname when the 2725af12a3e7SDag-Erling Smørgrav * authorization entry is added with xauth(1). This will be 2726af12a3e7SDag-Erling Smørgrav * different than the DISPLAY string for localhost displays. 2727af12a3e7SDag-Erling Smørgrav */ 2728af12a3e7SDag-Erling Smørgrav if (options.x11_use_localhost) { 2729a82e551fSDag-Erling Smørgrav snprintf(display, sizeof display, "localhost:%u.%u", 2730af12a3e7SDag-Erling Smørgrav s->display_number, s->screen); 2731a82e551fSDag-Erling Smørgrav snprintf(auth_display, sizeof auth_display, "unix:%u.%u", 2732af12a3e7SDag-Erling Smørgrav s->display_number, s->screen); 2733af12a3e7SDag-Erling Smørgrav s->display = xstrdup(display); 2734af12a3e7SDag-Erling Smørgrav s->auth_display = xstrdup(auth_display); 2735af12a3e7SDag-Erling Smørgrav } else { 2736989dd127SDag-Erling Smørgrav #ifdef IPADDR_IN_DISPLAY 2737989dd127SDag-Erling Smørgrav struct hostent *he; 2738989dd127SDag-Erling Smørgrav struct in_addr my_addr; 2739989dd127SDag-Erling Smørgrav 2740989dd127SDag-Erling Smørgrav he = gethostbyname(hostname); 2741989dd127SDag-Erling Smørgrav if (he == NULL) { 2742989dd127SDag-Erling Smørgrav error("Can't get IP address for X11 DISPLAY."); 2743989dd127SDag-Erling Smørgrav packet_send_debug("Can't get IP address for X11 DISPLAY."); 2744989dd127SDag-Erling Smørgrav return 0; 2745989dd127SDag-Erling Smørgrav } 2746989dd127SDag-Erling Smørgrav memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr)); 2747a82e551fSDag-Erling Smørgrav snprintf(display, sizeof display, "%.50s:%u.%u", inet_ntoa(my_addr), 2748989dd127SDag-Erling Smørgrav s->display_number, s->screen); 2749989dd127SDag-Erling Smørgrav #else 2750a82e551fSDag-Erling Smørgrav snprintf(display, sizeof display, "%.400s:%u.%u", hostname, 2751af12a3e7SDag-Erling Smørgrav s->display_number, s->screen); 2752989dd127SDag-Erling Smørgrav #endif 2753af12a3e7SDag-Erling Smørgrav s->display = xstrdup(display); 2754af12a3e7SDag-Erling Smørgrav s->auth_display = xstrdup(display); 2755af12a3e7SDag-Erling Smørgrav } 2756af12a3e7SDag-Erling Smørgrav 2757af12a3e7SDag-Erling Smørgrav return 1; 2758af12a3e7SDag-Erling Smørgrav } 2759af12a3e7SDag-Erling Smørgrav 2760af12a3e7SDag-Erling Smørgrav static void 2761ca3176e7SBrian Feldman do_authenticated2(Authctxt *authctxt) 2762a04a10f8SKris Kennaway { 2763af12a3e7SDag-Erling Smørgrav server_loop2(authctxt); 27641ec0d754SDag-Erling Smørgrav } 27651ec0d754SDag-Erling Smørgrav 27661ec0d754SDag-Erling Smørgrav void 27671ec0d754SDag-Erling Smørgrav do_cleanup(Authctxt *authctxt) 27681ec0d754SDag-Erling Smørgrav { 27691ec0d754SDag-Erling Smørgrav static int called = 0; 27701ec0d754SDag-Erling Smørgrav 27711ec0d754SDag-Erling Smørgrav debug("do_cleanup"); 27721ec0d754SDag-Erling Smørgrav 27731ec0d754SDag-Erling Smørgrav /* no cleanup if we're in the child for login shell */ 27741ec0d754SDag-Erling Smørgrav if (is_child) 27751ec0d754SDag-Erling Smørgrav return; 27761ec0d754SDag-Erling Smørgrav 27771ec0d754SDag-Erling Smørgrav /* avoid double cleanup */ 27781ec0d754SDag-Erling Smørgrav if (called) 27791ec0d754SDag-Erling Smørgrav return; 27801ec0d754SDag-Erling Smørgrav called = 1; 27811ec0d754SDag-Erling Smørgrav 2782d4af9e69SDag-Erling Smørgrav if (authctxt == NULL) 27831ec0d754SDag-Erling Smørgrav return; 2784d4af9e69SDag-Erling Smørgrav 2785d4af9e69SDag-Erling Smørgrav #ifdef USE_PAM 2786d4af9e69SDag-Erling Smørgrav if (options.use_pam) { 2787d4af9e69SDag-Erling Smørgrav sshpam_cleanup(); 2788d4af9e69SDag-Erling Smørgrav sshpam_thread_cleanup(); 2789d4af9e69SDag-Erling Smørgrav } 2790d4af9e69SDag-Erling Smørgrav #endif 2791d4af9e69SDag-Erling Smørgrav 2792d4af9e69SDag-Erling Smørgrav if (!authctxt->authenticated) 2793d4af9e69SDag-Erling Smørgrav return; 2794d4af9e69SDag-Erling Smørgrav 27951ec0d754SDag-Erling Smørgrav #ifdef KRB5 27961ec0d754SDag-Erling Smørgrav if (options.kerberos_ticket_cleanup && 27971ec0d754SDag-Erling Smørgrav authctxt->krb5_ctx) 27981ec0d754SDag-Erling Smørgrav krb5_cleanup_proc(authctxt); 2799cf2b5f3bSDag-Erling Smørgrav #endif 28001ec0d754SDag-Erling Smørgrav 28011ec0d754SDag-Erling Smørgrav #ifdef GSSAPI 28021ec0d754SDag-Erling Smørgrav if (compat20 && options.gss_cleanup_creds) 28031ec0d754SDag-Erling Smørgrav ssh_gssapi_cleanup_creds(); 28041ec0d754SDag-Erling Smørgrav #endif 28051ec0d754SDag-Erling Smørgrav 28061ec0d754SDag-Erling Smørgrav /* remove agent socket */ 28071ec0d754SDag-Erling Smørgrav auth_sock_cleanup_proc(authctxt->pw); 28081ec0d754SDag-Erling Smørgrav 28091ec0d754SDag-Erling Smørgrav /* 28101ec0d754SDag-Erling Smørgrav * Cleanup ptys/utmp only if privsep is disabled, 28111ec0d754SDag-Erling Smørgrav * or if running in monitor. 28121ec0d754SDag-Erling Smørgrav */ 28131ec0d754SDag-Erling Smørgrav if (!use_privsep || mm_is_monitor()) 28141ec0d754SDag-Erling Smørgrav session_destroy_all(session_pty_cleanup2); 2815a04a10f8SKris Kennaway } 2816