1a04a10f8SKris Kennaway /* 2a04a10f8SKris Kennaway * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 3a04a10f8SKris Kennaway * All rights reserved 4c2d3a559SKris Kennaway * 5c2d3a559SKris Kennaway * As far as I am concerned, the code I have written for this software 6c2d3a559SKris Kennaway * can be used freely for any purpose. Any derived versions of this 7c2d3a559SKris Kennaway * software must be clearly marked as such, and if the derived work is 8c2d3a559SKris Kennaway * incompatible with the protocol description in the RFC file, it must be 9c2d3a559SKris Kennaway * called by a name other than "ssh" or "Secure Shell". 10c2d3a559SKris Kennaway * 11a04a10f8SKris Kennaway * SSH2 support by Markus Friedl. 12af12a3e7SDag-Erling Smørgrav * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 13e8aafc91SKris Kennaway * 14c2d3a559SKris Kennaway * Redistribution and use in source and binary forms, with or without 15c2d3a559SKris Kennaway * modification, are permitted provided that the following conditions 16c2d3a559SKris Kennaway * are met: 17c2d3a559SKris Kennaway * 1. Redistributions of source code must retain the above copyright 18c2d3a559SKris Kennaway * notice, this list of conditions and the following disclaimer. 19c2d3a559SKris Kennaway * 2. Redistributions in binary form must reproduce the above copyright 20c2d3a559SKris Kennaway * notice, this list of conditions and the following disclaimer in the 21c2d3a559SKris Kennaway * documentation and/or other materials provided with the distribution. 22c2d3a559SKris Kennaway * 23c2d3a559SKris Kennaway * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24c2d3a559SKris Kennaway * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25c2d3a559SKris Kennaway * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26c2d3a559SKris Kennaway * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27c2d3a559SKris Kennaway * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28c2d3a559SKris Kennaway * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29c2d3a559SKris Kennaway * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30c2d3a559SKris Kennaway * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31c2d3a559SKris Kennaway * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32c2d3a559SKris Kennaway * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33a04a10f8SKris Kennaway */ 34a04a10f8SKris Kennaway 35a04a10f8SKris Kennaway #include "includes.h" 36a82e551fSDag-Erling Smørgrav RCSID("$OpenBSD: session.c,v 1.142 2002/06/26 13:49:26 deraadt Exp $"); 37c62005fcSDag-Erling Smørgrav RCSID("$FreeBSD$"); 38a04a10f8SKris Kennaway 39a04a10f8SKris Kennaway #include "ssh.h" 40ca3176e7SBrian Feldman #include "ssh1.h" 41ca3176e7SBrian Feldman #include "ssh2.h" 42ca3176e7SBrian Feldman #include "xmalloc.h" 43ca3176e7SBrian Feldman #include "sshpty.h" 44a04a10f8SKris Kennaway #include "packet.h" 45a04a10f8SKris Kennaway #include "buffer.h" 46a04a10f8SKris Kennaway #include "mpaux.h" 47a04a10f8SKris Kennaway #include "uidswap.h" 48a04a10f8SKris Kennaway #include "compat.h" 49a04a10f8SKris Kennaway #include "channels.h" 50a04a10f8SKris Kennaway #include "bufaux.h" 51a04a10f8SKris Kennaway #include "auth.h" 52c2d3a559SKris Kennaway #include "auth-options.h" 53ca3176e7SBrian Feldman #include "pathnames.h" 54ca3176e7SBrian Feldman #include "log.h" 55ca3176e7SBrian Feldman #include "servconf.h" 56ca3176e7SBrian Feldman #include "sshlogin.h" 57ca3176e7SBrian Feldman #include "serverloop.h" 58ca3176e7SBrian Feldman #include "canohost.h" 59ca3176e7SBrian Feldman #include "session.h" 6080628bacSDag-Erling Smørgrav #include "monitor_wrap.h" 61a04a10f8SKris Kennaway 62989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN 63989dd127SDag-Erling Smørgrav #include <windows.h> 64989dd127SDag-Erling Smørgrav #include <sys/cygwin.h> 65989dd127SDag-Erling Smørgrav #define is_winnt (GetVersion() < 0x80000000) 66c2d3a559SKris Kennaway #endif 67e8aafc91SKris Kennaway 68a04a10f8SKris Kennaway /* func */ 69a04a10f8SKris Kennaway 70a04a10f8SKris Kennaway Session *session_new(void); 71af12a3e7SDag-Erling Smørgrav void session_set_fds(Session *, int, int, int); 7280628bacSDag-Erling Smørgrav void session_pty_cleanup(void *); 73af12a3e7SDag-Erling Smørgrav void session_proctitle(Session *); 74af12a3e7SDag-Erling Smørgrav int session_setup_x11fwd(Session *); 75af12a3e7SDag-Erling Smørgrav void do_exec_pty(Session *, const char *); 76af12a3e7SDag-Erling Smørgrav void do_exec_no_pty(Session *, const char *); 77af12a3e7SDag-Erling Smørgrav void do_exec(Session *, const char *); 78af12a3e7SDag-Erling Smørgrav void do_login(Session *, const char *); 79989dd127SDag-Erling Smørgrav #ifdef LOGIN_NEEDS_UTMPX 80989dd127SDag-Erling Smørgrav static void do_pre_login(Session *s); 81989dd127SDag-Erling Smørgrav #endif 82af12a3e7SDag-Erling Smørgrav void do_child(Session *, const char *); 83ca3176e7SBrian Feldman void do_motd(void); 84af12a3e7SDag-Erling Smørgrav int check_quietlogin(Session *, const char *); 85a04a10f8SKris Kennaway 86af12a3e7SDag-Erling Smørgrav static void do_authenticated1(Authctxt *); 87af12a3e7SDag-Erling Smørgrav static void do_authenticated2(Authctxt *); 88af12a3e7SDag-Erling Smørgrav 89af12a3e7SDag-Erling Smørgrav static int session_pty_req(Session *); 90a04a10f8SKris Kennaway 91a04a10f8SKris Kennaway /* import */ 92a04a10f8SKris Kennaway extern ServerOptions options; 93a04a10f8SKris Kennaway extern char *__progname; 94a04a10f8SKris Kennaway extern int log_stderr; 95a04a10f8SKris Kennaway extern int debug_flag; 96ca3176e7SBrian Feldman extern u_int utmp_len; 97c2d3a559SKris Kennaway extern int startup_pipe; 98ca3176e7SBrian Feldman extern void destroy_sensitive_data(void); 99a04a10f8SKris Kennaway 100c2d3a559SKris Kennaway /* original command from peer. */ 101af12a3e7SDag-Erling Smørgrav const char *original_command = NULL; 102c2d3a559SKris Kennaway 103a04a10f8SKris Kennaway /* data */ 104a04a10f8SKris Kennaway #define MAX_SESSIONS 10 105a04a10f8SKris Kennaway Session sessions[MAX_SESSIONS]; 106a04a10f8SKris Kennaway 107989dd127SDag-Erling Smørgrav #ifdef WITH_AIXAUTHENTICATE 108989dd127SDag-Erling Smørgrav char *aixloginmsg; 109989dd127SDag-Erling Smørgrav #endif /* WITH_AIXAUTHENTICATE */ 110989dd127SDag-Erling Smørgrav 111c2d3a559SKris Kennaway #ifdef HAVE_LOGIN_CAP 11280628bacSDag-Erling Smørgrav login_cap_t *lc; 113c2d3a559SKris Kennaway #endif 114a04a10f8SKris Kennaway 11580628bacSDag-Erling Smørgrav /* Name and directory of socket for authentication agent forwarding. */ 11680628bacSDag-Erling Smørgrav static char *auth_sock_name = NULL; 11780628bacSDag-Erling Smørgrav static char *auth_sock_dir = NULL; 11880628bacSDag-Erling Smørgrav 11980628bacSDag-Erling Smørgrav /* removes the agent forwarding socket */ 12080628bacSDag-Erling Smørgrav 12180628bacSDag-Erling Smørgrav static void 12280628bacSDag-Erling Smørgrav auth_sock_cleanup_proc(void *_pw) 12380628bacSDag-Erling Smørgrav { 12480628bacSDag-Erling Smørgrav struct passwd *pw = _pw; 12580628bacSDag-Erling Smørgrav 12680628bacSDag-Erling Smørgrav if (auth_sock_name != NULL) { 12780628bacSDag-Erling Smørgrav temporarily_use_uid(pw); 12880628bacSDag-Erling Smørgrav unlink(auth_sock_name); 12980628bacSDag-Erling Smørgrav rmdir(auth_sock_dir); 13080628bacSDag-Erling Smørgrav auth_sock_name = NULL; 13180628bacSDag-Erling Smørgrav restore_uid(); 13280628bacSDag-Erling Smørgrav } 13380628bacSDag-Erling Smørgrav } 13480628bacSDag-Erling Smørgrav 13580628bacSDag-Erling Smørgrav static int 13680628bacSDag-Erling Smørgrav auth_input_request_forwarding(struct passwd * pw) 13780628bacSDag-Erling Smørgrav { 13880628bacSDag-Erling Smørgrav Channel *nc; 13980628bacSDag-Erling Smørgrav int sock; 14080628bacSDag-Erling Smørgrav struct sockaddr_un sunaddr; 14180628bacSDag-Erling Smørgrav 14280628bacSDag-Erling Smørgrav if (auth_sock_name != NULL) { 14380628bacSDag-Erling Smørgrav error("authentication forwarding requested twice."); 14480628bacSDag-Erling Smørgrav return 0; 14580628bacSDag-Erling Smørgrav } 14680628bacSDag-Erling Smørgrav 14780628bacSDag-Erling Smørgrav /* Temporarily drop privileged uid for mkdir/bind. */ 14880628bacSDag-Erling Smørgrav temporarily_use_uid(pw); 14980628bacSDag-Erling Smørgrav 15080628bacSDag-Erling Smørgrav /* Allocate a buffer for the socket name, and format the name. */ 15180628bacSDag-Erling Smørgrav auth_sock_name = xmalloc(MAXPATHLEN); 15280628bacSDag-Erling Smørgrav auth_sock_dir = xmalloc(MAXPATHLEN); 15380628bacSDag-Erling Smørgrav strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXX", MAXPATHLEN); 15480628bacSDag-Erling Smørgrav 15580628bacSDag-Erling Smørgrav /* Create private directory for socket */ 15680628bacSDag-Erling Smørgrav if (mkdtemp(auth_sock_dir) == NULL) { 15780628bacSDag-Erling Smørgrav packet_send_debug("Agent forwarding disabled: " 15880628bacSDag-Erling Smørgrav "mkdtemp() failed: %.100s", strerror(errno)); 15980628bacSDag-Erling Smørgrav restore_uid(); 16080628bacSDag-Erling Smørgrav xfree(auth_sock_name); 16180628bacSDag-Erling Smørgrav xfree(auth_sock_dir); 16280628bacSDag-Erling Smørgrav auth_sock_name = NULL; 16380628bacSDag-Erling Smørgrav auth_sock_dir = NULL; 16480628bacSDag-Erling Smørgrav return 0; 16580628bacSDag-Erling Smørgrav } 16680628bacSDag-Erling Smørgrav snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld", 16780628bacSDag-Erling Smørgrav auth_sock_dir, (long) getpid()); 16880628bacSDag-Erling Smørgrav 16980628bacSDag-Erling Smørgrav /* delete agent socket on fatal() */ 17080628bacSDag-Erling Smørgrav fatal_add_cleanup(auth_sock_cleanup_proc, pw); 17180628bacSDag-Erling Smørgrav 17280628bacSDag-Erling Smørgrav /* Create the socket. */ 17380628bacSDag-Erling Smørgrav sock = socket(AF_UNIX, SOCK_STREAM, 0); 17480628bacSDag-Erling Smørgrav if (sock < 0) 17580628bacSDag-Erling Smørgrav packet_disconnect("socket: %.100s", strerror(errno)); 17680628bacSDag-Erling Smørgrav 17780628bacSDag-Erling Smørgrav /* Bind it to the name. */ 17880628bacSDag-Erling Smørgrav memset(&sunaddr, 0, sizeof(sunaddr)); 17980628bacSDag-Erling Smørgrav sunaddr.sun_family = AF_UNIX; 18080628bacSDag-Erling Smørgrav strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path)); 18180628bacSDag-Erling Smørgrav 18280628bacSDag-Erling Smørgrav if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) 18380628bacSDag-Erling Smørgrav packet_disconnect("bind: %.100s", strerror(errno)); 18480628bacSDag-Erling Smørgrav 18580628bacSDag-Erling Smørgrav /* Restore the privileged uid. */ 18680628bacSDag-Erling Smørgrav restore_uid(); 18780628bacSDag-Erling Smørgrav 18880628bacSDag-Erling Smørgrav /* Start listening on the socket. */ 18980628bacSDag-Erling Smørgrav if (listen(sock, 5) < 0) 19080628bacSDag-Erling Smørgrav packet_disconnect("listen: %.100s", strerror(errno)); 19180628bacSDag-Erling Smørgrav 19280628bacSDag-Erling Smørgrav /* Allocate a channel for the authentication agent socket. */ 19380628bacSDag-Erling Smørgrav nc = channel_new("auth socket", 19480628bacSDag-Erling Smørgrav SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, 19580628bacSDag-Erling Smørgrav CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 19680628bacSDag-Erling Smørgrav 0, xstrdup("auth socket"), 1); 19780628bacSDag-Erling Smørgrav strlcpy(nc->path, auth_sock_name, sizeof(nc->path)); 19880628bacSDag-Erling Smørgrav return 1; 19980628bacSDag-Erling Smørgrav } 20080628bacSDag-Erling Smørgrav 20180628bacSDag-Erling Smørgrav 202ca3176e7SBrian Feldman void 203ca3176e7SBrian Feldman do_authenticated(Authctxt *authctxt) 204ca3176e7SBrian Feldman { 205ca3176e7SBrian Feldman /* 206ca3176e7SBrian Feldman * Cancel the alarm we set to limit the time taken for 207ca3176e7SBrian Feldman * authentication. 208ca3176e7SBrian Feldman */ 209ca3176e7SBrian Feldman alarm(0); 210ca3176e7SBrian Feldman if (startup_pipe != -1) { 211ca3176e7SBrian Feldman close(startup_pipe); 212ca3176e7SBrian Feldman startup_pipe = -1; 213ca3176e7SBrian Feldman } 214989dd127SDag-Erling Smørgrav #ifdef WITH_AIXAUTHENTICATE 215989dd127SDag-Erling Smørgrav /* We don't have a pty yet, so just label the line as "ssh" */ 216989dd127SDag-Erling Smørgrav if (loginsuccess(authctxt->user, 217989dd127SDag-Erling Smørgrav get_canonical_hostname(options.verify_reverse_mapping), 218989dd127SDag-Erling Smørgrav "ssh", &aixloginmsg) < 0) 219989dd127SDag-Erling Smørgrav aixloginmsg = NULL; 220989dd127SDag-Erling Smørgrav #endif /* WITH_AIXAUTHENTICATE */ 221989dd127SDag-Erling Smørgrav 222ca3176e7SBrian Feldman /* setup the channel layer */ 223ca3176e7SBrian Feldman if (!no_port_forwarding_flag && options.allow_tcp_forwarding) 224ca3176e7SBrian Feldman channel_permit_all_opens(); 225ca3176e7SBrian Feldman 226ca3176e7SBrian Feldman if (compat20) 227ca3176e7SBrian Feldman do_authenticated2(authctxt); 228ca3176e7SBrian Feldman else 229ca3176e7SBrian Feldman do_authenticated1(authctxt); 230e9fd63dfSBrian Feldman 231af12a3e7SDag-Erling Smørgrav /* remove agent socket */ 23280628bacSDag-Erling Smørgrav if (auth_sock_name != NULL) 233e9fd63dfSBrian Feldman auth_sock_cleanup_proc(authctxt->pw); 234af12a3e7SDag-Erling Smørgrav #ifdef KRB4 235af12a3e7SDag-Erling Smørgrav if (options.kerberos_ticket_cleanup) 236af12a3e7SDag-Erling Smørgrav krb4_cleanup_proc(authctxt); 237af12a3e7SDag-Erling Smørgrav #endif 238af12a3e7SDag-Erling Smørgrav #ifdef KRB5 239af12a3e7SDag-Erling Smørgrav if (options.kerberos_ticket_cleanup) 240af12a3e7SDag-Erling Smørgrav krb5_cleanup_proc(authctxt); 241af12a3e7SDag-Erling Smørgrav #endif 242a04a10f8SKris Kennaway } 243a04a10f8SKris Kennaway 244a04a10f8SKris Kennaway /* 245a04a10f8SKris Kennaway * Prepares for an interactive session. This is called after the user has 246a04a10f8SKris Kennaway * been successfully authenticated. During this message exchange, pseudo 247a04a10f8SKris Kennaway * terminals are allocated, X11, TCP/IP, and authentication agent forwardings 248a04a10f8SKris Kennaway * are requested, etc. 249a04a10f8SKris Kennaway */ 250af12a3e7SDag-Erling Smørgrav static void 251ca3176e7SBrian Feldman do_authenticated1(Authctxt *authctxt) 252a04a10f8SKris Kennaway { 253a04a10f8SKris Kennaway Session *s; 254a04a10f8SKris Kennaway char *command; 255af12a3e7SDag-Erling Smørgrav int success, type, screen_flag; 256a82e551fSDag-Erling Smørgrav int enable_compression_after_reply = 0; 257a82e551fSDag-Erling Smørgrav u_int proto_len, data_len, dlen, compression_level = 0; 258a04a10f8SKris Kennaway 259a04a10f8SKris Kennaway s = session_new(); 260af12a3e7SDag-Erling Smørgrav s->authctxt = authctxt; 261ca3176e7SBrian Feldman s->pw = authctxt->pw; 262c2d3a559SKris Kennaway 263a04a10f8SKris Kennaway /* 264a04a10f8SKris Kennaway * We stay in this loop until the client requests to execute a shell 265a04a10f8SKris Kennaway * or a command. 266a04a10f8SKris Kennaway */ 267a04a10f8SKris Kennaway for (;;) { 268ca3176e7SBrian Feldman success = 0; 269a04a10f8SKris Kennaway 270a04a10f8SKris Kennaway /* Get a packet from the client. */ 271af12a3e7SDag-Erling Smørgrav type = packet_read(); 272a04a10f8SKris Kennaway 273a04a10f8SKris Kennaway /* Process the packet. */ 274a04a10f8SKris Kennaway switch (type) { 275a04a10f8SKris Kennaway case SSH_CMSG_REQUEST_COMPRESSION: 276a04a10f8SKris Kennaway compression_level = packet_get_int(); 277af12a3e7SDag-Erling Smørgrav packet_check_eom(); 278a04a10f8SKris Kennaway if (compression_level < 1 || compression_level > 9) { 279a04a10f8SKris Kennaway packet_send_debug("Received illegal compression level %d.", 280a04a10f8SKris Kennaway compression_level); 281a04a10f8SKris Kennaway break; 282a04a10f8SKris Kennaway } 28380628bacSDag-Erling Smørgrav if (!options.compression) { 28480628bacSDag-Erling Smørgrav debug2("compression disabled"); 28580628bacSDag-Erling Smørgrav break; 28680628bacSDag-Erling Smørgrav } 287a04a10f8SKris Kennaway /* Enable compression after we have responded with SUCCESS. */ 288a04a10f8SKris Kennaway enable_compression_after_reply = 1; 289a04a10f8SKris Kennaway success = 1; 290a04a10f8SKris Kennaway break; 291a04a10f8SKris Kennaway 292a04a10f8SKris Kennaway case SSH_CMSG_REQUEST_PTY: 293af12a3e7SDag-Erling Smørgrav success = session_pty_req(s); 294a04a10f8SKris Kennaway break; 295a04a10f8SKris Kennaway 296a04a10f8SKris Kennaway case SSH_CMSG_X11_REQUEST_FORWARDING: 297a04a10f8SKris Kennaway s->auth_proto = packet_get_string(&proto_len); 298a04a10f8SKris Kennaway s->auth_data = packet_get_string(&data_len); 299a04a10f8SKris Kennaway 300ca3176e7SBrian Feldman screen_flag = packet_get_protocol_flags() & 301ca3176e7SBrian Feldman SSH_PROTOFLAG_SCREEN_NUMBER; 302ca3176e7SBrian Feldman debug2("SSH_PROTOFLAG_SCREEN_NUMBER: %d", screen_flag); 303ca3176e7SBrian Feldman 304ca3176e7SBrian Feldman if (packet_remaining() == 4) { 305ca3176e7SBrian Feldman if (!screen_flag) 306ca3176e7SBrian Feldman debug2("Buggy client: " 307ca3176e7SBrian Feldman "X11 screen flag missing"); 308a04a10f8SKris Kennaway s->screen = packet_get_int(); 309ca3176e7SBrian Feldman } else { 310a04a10f8SKris Kennaway s->screen = 0; 311ca3176e7SBrian Feldman } 312af12a3e7SDag-Erling Smørgrav packet_check_eom(); 313af12a3e7SDag-Erling Smørgrav success = session_setup_x11fwd(s); 314af12a3e7SDag-Erling Smørgrav if (!success) { 315af12a3e7SDag-Erling Smørgrav xfree(s->auth_proto); 316af12a3e7SDag-Erling Smørgrav xfree(s->auth_data); 317af12a3e7SDag-Erling Smørgrav s->auth_proto = NULL; 318af12a3e7SDag-Erling Smørgrav s->auth_data = NULL; 319a04a10f8SKris Kennaway } 320a04a10f8SKris Kennaway break; 321a04a10f8SKris Kennaway 322a04a10f8SKris Kennaway case SSH_CMSG_AGENT_REQUEST_FORWARDING: 323a04a10f8SKris Kennaway if (no_agent_forwarding_flag || compat13) { 324a04a10f8SKris Kennaway debug("Authentication agent forwarding not permitted for this authentication."); 325a04a10f8SKris Kennaway break; 326a04a10f8SKris Kennaway } 327a04a10f8SKris Kennaway debug("Received authentication agent forwarding request."); 328ca3176e7SBrian Feldman success = auth_input_request_forwarding(s->pw); 329a04a10f8SKris Kennaway break; 330a04a10f8SKris Kennaway 331a04a10f8SKris Kennaway case SSH_CMSG_PORT_FORWARD_REQUEST: 332a04a10f8SKris Kennaway if (no_port_forwarding_flag) { 333a04a10f8SKris Kennaway debug("Port forwarding not permitted for this authentication."); 334a04a10f8SKris Kennaway break; 335a04a10f8SKris Kennaway } 33609958426SBrian Feldman if (!options.allow_tcp_forwarding) { 33709958426SBrian Feldman debug("Port forwarding not permitted."); 33809958426SBrian Feldman break; 33909958426SBrian Feldman } 340a04a10f8SKris Kennaway debug("Received TCP/IP port forwarding request."); 341ca3176e7SBrian Feldman channel_input_port_forward_request(s->pw->pw_uid == 0, options.gateway_ports); 342a04a10f8SKris Kennaway success = 1; 343a04a10f8SKris Kennaway break; 344a04a10f8SKris Kennaway 345a04a10f8SKris Kennaway case SSH_CMSG_MAX_PACKET_SIZE: 346a04a10f8SKris Kennaway if (packet_set_maxsize(packet_get_int()) > 0) 347a04a10f8SKris Kennaway success = 1; 348a04a10f8SKris Kennaway break; 349a04a10f8SKris Kennaway 350af12a3e7SDag-Erling Smørgrav #if defined(AFS) || defined(KRB5) 351af12a3e7SDag-Erling Smørgrav case SSH_CMSG_HAVE_KERBEROS_TGT: 352af12a3e7SDag-Erling Smørgrav if (!options.kerberos_tgt_passing) { 353af12a3e7SDag-Erling Smørgrav verbose("Kerberos TGT passing disabled."); 354af12a3e7SDag-Erling Smørgrav } else { 355af12a3e7SDag-Erling Smørgrav char *kdata = packet_get_string(&dlen); 356af12a3e7SDag-Erling Smørgrav packet_check_eom(); 357af12a3e7SDag-Erling Smørgrav 358af12a3e7SDag-Erling Smørgrav /* XXX - 0x41, see creds_to_radix version */ 359af12a3e7SDag-Erling Smørgrav if (kdata[0] != 0x41) { 360af12a3e7SDag-Erling Smørgrav #ifdef KRB5 361af12a3e7SDag-Erling Smørgrav krb5_data tgt; 362af12a3e7SDag-Erling Smørgrav tgt.data = kdata; 363af12a3e7SDag-Erling Smørgrav tgt.length = dlen; 364af12a3e7SDag-Erling Smørgrav 365af12a3e7SDag-Erling Smørgrav if (auth_krb5_tgt(s->authctxt, &tgt)) 366af12a3e7SDag-Erling Smørgrav success = 1; 367af12a3e7SDag-Erling Smørgrav else 368af12a3e7SDag-Erling Smørgrav verbose("Kerberos v5 TGT refused for %.100s", s->authctxt->user); 369af12a3e7SDag-Erling Smørgrav #endif /* KRB5 */ 370af12a3e7SDag-Erling Smørgrav } else { 371af12a3e7SDag-Erling Smørgrav #ifdef AFS 372af12a3e7SDag-Erling Smørgrav if (auth_krb4_tgt(s->authctxt, kdata)) 373af12a3e7SDag-Erling Smørgrav success = 1; 374af12a3e7SDag-Erling Smørgrav else 375af12a3e7SDag-Erling Smørgrav verbose("Kerberos v4 TGT refused for %.100s", s->authctxt->user); 376af12a3e7SDag-Erling Smørgrav #endif /* AFS */ 377af12a3e7SDag-Erling Smørgrav } 378af12a3e7SDag-Erling Smørgrav xfree(kdata); 379af12a3e7SDag-Erling Smørgrav } 380af12a3e7SDag-Erling Smørgrav break; 381af12a3e7SDag-Erling Smørgrav #endif /* AFS || KRB5 */ 382af12a3e7SDag-Erling Smørgrav 383af12a3e7SDag-Erling Smørgrav #ifdef AFS 384af12a3e7SDag-Erling Smørgrav case SSH_CMSG_HAVE_AFS_TOKEN: 385af12a3e7SDag-Erling Smørgrav if (!options.afs_token_passing || !k_hasafs()) { 386af12a3e7SDag-Erling Smørgrav verbose("AFS token passing disabled."); 387af12a3e7SDag-Erling Smørgrav } else { 388af12a3e7SDag-Erling Smørgrav /* Accept AFS token. */ 389af12a3e7SDag-Erling Smørgrav char *token = packet_get_string(&dlen); 390af12a3e7SDag-Erling Smørgrav packet_check_eom(); 391af12a3e7SDag-Erling Smørgrav 392af12a3e7SDag-Erling Smørgrav if (auth_afs_token(s->authctxt, token)) 393af12a3e7SDag-Erling Smørgrav success = 1; 394af12a3e7SDag-Erling Smørgrav else 395af12a3e7SDag-Erling Smørgrav verbose("AFS token refused for %.100s", 396af12a3e7SDag-Erling Smørgrav s->authctxt->user); 397af12a3e7SDag-Erling Smørgrav xfree(token); 398af12a3e7SDag-Erling Smørgrav } 399af12a3e7SDag-Erling Smørgrav break; 400af12a3e7SDag-Erling Smørgrav #endif /* AFS */ 401af12a3e7SDag-Erling Smørgrav 402a04a10f8SKris Kennaway case SSH_CMSG_EXEC_SHELL: 403a04a10f8SKris Kennaway case SSH_CMSG_EXEC_CMD: 404a04a10f8SKris Kennaway if (type == SSH_CMSG_EXEC_CMD) { 405a04a10f8SKris Kennaway command = packet_get_string(&dlen); 406a04a10f8SKris Kennaway debug("Exec command '%.500s'", command); 407af12a3e7SDag-Erling Smørgrav do_exec(s, command); 408a04a10f8SKris Kennaway xfree(command); 409af12a3e7SDag-Erling Smørgrav } else { 410af12a3e7SDag-Erling Smørgrav do_exec(s, NULL); 411af12a3e7SDag-Erling Smørgrav } 412af12a3e7SDag-Erling Smørgrav packet_check_eom(); 413af12a3e7SDag-Erling Smørgrav session_close(s); 414a04a10f8SKris Kennaway return; 415a04a10f8SKris Kennaway 416a04a10f8SKris Kennaway default: 417a04a10f8SKris Kennaway /* 418a04a10f8SKris Kennaway * Any unknown messages in this phase are ignored, 419a04a10f8SKris Kennaway * and a failure message is returned. 420a04a10f8SKris Kennaway */ 421a04a10f8SKris Kennaway log("Unknown packet type received after authentication: %d", type); 422a04a10f8SKris Kennaway } 423a04a10f8SKris Kennaway packet_start(success ? SSH_SMSG_SUCCESS : SSH_SMSG_FAILURE); 424a04a10f8SKris Kennaway packet_send(); 425a04a10f8SKris Kennaway packet_write_wait(); 426a04a10f8SKris Kennaway 427a04a10f8SKris Kennaway /* Enable compression now that we have replied if appropriate. */ 428a04a10f8SKris Kennaway if (enable_compression_after_reply) { 429a04a10f8SKris Kennaway enable_compression_after_reply = 0; 430a04a10f8SKris Kennaway packet_start_compression(compression_level); 431a04a10f8SKris Kennaway } 432a04a10f8SKris Kennaway } 433a04a10f8SKris Kennaway } 434a04a10f8SKris Kennaway 435a04a10f8SKris Kennaway /* 436a04a10f8SKris Kennaway * This is called to fork and execute a command when we have no tty. This 437a04a10f8SKris Kennaway * will call do_child from the child, and server_loop from the parent after 438a04a10f8SKris Kennaway * setting up file descriptors and such. 439a04a10f8SKris Kennaway */ 440a04a10f8SKris Kennaway void 441ca3176e7SBrian Feldman do_exec_no_pty(Session *s, const char *command) 442a04a10f8SKris Kennaway { 44380628bacSDag-Erling Smørgrav pid_t pid; 444a04a10f8SKris Kennaway 445a04a10f8SKris Kennaway #ifdef USE_PIPES 446a04a10f8SKris Kennaway int pin[2], pout[2], perr[2]; 447a04a10f8SKris Kennaway /* Allocate pipes for communicating with the program. */ 448a04a10f8SKris Kennaway if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0) 449a04a10f8SKris Kennaway packet_disconnect("Could not create pipes: %.100s", 450a04a10f8SKris Kennaway strerror(errno)); 451a04a10f8SKris Kennaway #else /* USE_PIPES */ 452a04a10f8SKris Kennaway int inout[2], err[2]; 453a04a10f8SKris Kennaway /* Uses socket pairs to communicate with the program. */ 454a04a10f8SKris Kennaway if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 || 455a04a10f8SKris Kennaway socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) 456a04a10f8SKris Kennaway packet_disconnect("Could not create socket pairs: %.100s", 457a04a10f8SKris Kennaway strerror(errno)); 458a04a10f8SKris Kennaway #endif /* USE_PIPES */ 459a04a10f8SKris Kennaway if (s == NULL) 460a04a10f8SKris Kennaway fatal("do_exec_no_pty: no session"); 461a04a10f8SKris Kennaway 462a04a10f8SKris Kennaway session_proctitle(s); 463a04a10f8SKris Kennaway 464989dd127SDag-Erling Smørgrav #if defined(USE_PAM) 465989dd127SDag-Erling Smørgrav do_pam_session(s->pw->pw_name, NULL); 466989dd127SDag-Erling Smørgrav do_pam_setcred(1); 467989dd127SDag-Erling Smørgrav if (is_pam_password_change_required()) 468989dd127SDag-Erling Smørgrav packet_disconnect("Password change required but no " 469989dd127SDag-Erling Smørgrav "TTY available"); 47009958426SBrian Feldman #endif /* USE_PAM */ 47109958426SBrian Feldman 472a04a10f8SKris Kennaway /* Fork the child. */ 473a04a10f8SKris Kennaway if ((pid = fork()) == 0) { 474a04a10f8SKris Kennaway /* Child. Reinitialize the log since the pid has changed. */ 475a04a10f8SKris Kennaway log_init(__progname, options.log_level, options.log_facility, log_stderr); 476a04a10f8SKris Kennaway 477a04a10f8SKris Kennaway /* 478a04a10f8SKris Kennaway * Create a new session and process group since the 4.4BSD 479a04a10f8SKris Kennaway * setlogin() affects the entire process group. 480a04a10f8SKris Kennaway */ 481a04a10f8SKris Kennaway if (setsid() < 0) 482a04a10f8SKris Kennaway error("setsid failed: %.100s", strerror(errno)); 483a04a10f8SKris Kennaway 484a04a10f8SKris Kennaway #ifdef USE_PIPES 485a04a10f8SKris Kennaway /* 486a04a10f8SKris Kennaway * Redirect stdin. We close the parent side of the socket 487a04a10f8SKris Kennaway * pair, and make the child side the standard input. 488a04a10f8SKris Kennaway */ 489a04a10f8SKris Kennaway close(pin[1]); 490a04a10f8SKris Kennaway if (dup2(pin[0], 0) < 0) 491a04a10f8SKris Kennaway perror("dup2 stdin"); 492a04a10f8SKris Kennaway close(pin[0]); 493a04a10f8SKris Kennaway 494a04a10f8SKris Kennaway /* Redirect stdout. */ 495a04a10f8SKris Kennaway close(pout[0]); 496a04a10f8SKris Kennaway if (dup2(pout[1], 1) < 0) 497a04a10f8SKris Kennaway perror("dup2 stdout"); 498a04a10f8SKris Kennaway close(pout[1]); 499a04a10f8SKris Kennaway 500a04a10f8SKris Kennaway /* Redirect stderr. */ 501a04a10f8SKris Kennaway close(perr[0]); 502a04a10f8SKris Kennaway if (dup2(perr[1], 2) < 0) 503a04a10f8SKris Kennaway perror("dup2 stderr"); 504a04a10f8SKris Kennaway close(perr[1]); 505a04a10f8SKris Kennaway #else /* USE_PIPES */ 506a04a10f8SKris Kennaway /* 507a04a10f8SKris Kennaway * Redirect stdin, stdout, and stderr. Stdin and stdout will 508a04a10f8SKris Kennaway * use the same socket, as some programs (particularly rdist) 509a04a10f8SKris Kennaway * seem to depend on it. 510a04a10f8SKris Kennaway */ 511a04a10f8SKris Kennaway close(inout[1]); 512a04a10f8SKris Kennaway close(err[1]); 513a04a10f8SKris Kennaway if (dup2(inout[0], 0) < 0) /* stdin */ 514a04a10f8SKris Kennaway perror("dup2 stdin"); 515a04a10f8SKris Kennaway if (dup2(inout[0], 1) < 0) /* stdout. Note: same socket as stdin. */ 516a04a10f8SKris Kennaway perror("dup2 stdout"); 517a04a10f8SKris Kennaway if (dup2(err[0], 2) < 0) /* stderr */ 518a04a10f8SKris Kennaway perror("dup2 stderr"); 519a04a10f8SKris Kennaway #endif /* USE_PIPES */ 520a04a10f8SKris Kennaway 521a04a10f8SKris Kennaway /* Do processing for the child (exec command etc). */ 522ca3176e7SBrian Feldman do_child(s, command); 523a04a10f8SKris Kennaway /* NOTREACHED */ 524a04a10f8SKris Kennaway } 525989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN 526989dd127SDag-Erling Smørgrav if (is_winnt) 527989dd127SDag-Erling Smørgrav cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); 528989dd127SDag-Erling Smørgrav #endif 529a04a10f8SKris Kennaway if (pid < 0) 530a04a10f8SKris Kennaway packet_disconnect("fork failed: %.100s", strerror(errno)); 531a04a10f8SKris Kennaway s->pid = pid; 532ca3176e7SBrian Feldman /* Set interactive/non-interactive mode. */ 533ca3176e7SBrian Feldman packet_set_interactive(s->display != NULL); 534a04a10f8SKris Kennaway #ifdef USE_PIPES 535a04a10f8SKris Kennaway /* We are the parent. Close the child sides of the pipes. */ 536a04a10f8SKris Kennaway close(pin[0]); 537a04a10f8SKris Kennaway close(pout[1]); 538a04a10f8SKris Kennaway close(perr[1]); 539a04a10f8SKris Kennaway 540a04a10f8SKris Kennaway if (compat20) { 541ca3176e7SBrian Feldman session_set_fds(s, pin[1], pout[0], s->is_subsystem ? -1 : perr[0]); 542a04a10f8SKris Kennaway } else { 543a04a10f8SKris Kennaway /* Enter the interactive session. */ 544a04a10f8SKris Kennaway server_loop(pid, pin[1], pout[0], perr[0]); 545ca3176e7SBrian Feldman /* server_loop has closed pin[1], pout[0], and perr[0]. */ 546a04a10f8SKris Kennaway } 547a04a10f8SKris Kennaway #else /* USE_PIPES */ 548a04a10f8SKris Kennaway /* We are the parent. Close the child sides of the socket pairs. */ 549a04a10f8SKris Kennaway close(inout[0]); 550a04a10f8SKris Kennaway close(err[0]); 551a04a10f8SKris Kennaway 552a04a10f8SKris Kennaway /* 553a04a10f8SKris Kennaway * Enter the interactive session. Note: server_loop must be able to 554a04a10f8SKris Kennaway * handle the case that fdin and fdout are the same. 555a04a10f8SKris Kennaway */ 556a04a10f8SKris Kennaway if (compat20) { 557ca3176e7SBrian Feldman session_set_fds(s, inout[1], inout[1], s->is_subsystem ? -1 : err[1]); 558a04a10f8SKris Kennaway } else { 559a04a10f8SKris Kennaway server_loop(pid, inout[1], inout[1], err[1]); 560a04a10f8SKris Kennaway /* server_loop has closed inout[1] and err[1]. */ 561a04a10f8SKris Kennaway } 562a04a10f8SKris Kennaway #endif /* USE_PIPES */ 563a04a10f8SKris Kennaway } 564a04a10f8SKris Kennaway 565a04a10f8SKris Kennaway /* 566a04a10f8SKris Kennaway * This is called to fork and execute a command when we have a tty. This 567a04a10f8SKris Kennaway * will call do_child from the child, and server_loop from the parent after 568a04a10f8SKris Kennaway * setting up file descriptors, controlling tty, updating wtmp, utmp, 569a04a10f8SKris Kennaway * lastlog, and other such operations. 570a04a10f8SKris Kennaway */ 571a04a10f8SKris Kennaway void 572ca3176e7SBrian Feldman do_exec_pty(Session *s, const char *command) 573a04a10f8SKris Kennaway { 574a04a10f8SKris Kennaway int fdout, ptyfd, ttyfd, ptymaster; 575a04a10f8SKris Kennaway pid_t pid; 576a04a10f8SKris Kennaway 577a04a10f8SKris Kennaway if (s == NULL) 578a04a10f8SKris Kennaway fatal("do_exec_pty: no session"); 579a04a10f8SKris Kennaway ptyfd = s->ptyfd; 580a04a10f8SKris Kennaway ttyfd = s->ttyfd; 581a04a10f8SKris Kennaway 582989dd127SDag-Erling Smørgrav #if defined(USE_PAM) 583989dd127SDag-Erling Smørgrav do_pam_session(s->pw->pw_name, s->tty); 584989dd127SDag-Erling Smørgrav do_pam_setcred(1); 585989dd127SDag-Erling Smørgrav #endif 58609958426SBrian Feldman 587a04a10f8SKris Kennaway /* Fork the child. */ 588a04a10f8SKris Kennaway if ((pid = fork()) == 0) { 589af12a3e7SDag-Erling Smørgrav 590c2d3a559SKris Kennaway /* Child. Reinitialize the log because the pid has changed. */ 591a04a10f8SKris Kennaway log_init(__progname, options.log_level, options.log_facility, log_stderr); 592a04a10f8SKris Kennaway /* Close the master side of the pseudo tty. */ 593a04a10f8SKris Kennaway close(ptyfd); 594a04a10f8SKris Kennaway 595a04a10f8SKris Kennaway /* Make the pseudo tty our controlling tty. */ 596a04a10f8SKris Kennaway pty_make_controlling_tty(&ttyfd, s->tty); 597a04a10f8SKris Kennaway 598af12a3e7SDag-Erling Smørgrav /* Redirect stdin/stdout/stderr from the pseudo tty. */ 599af12a3e7SDag-Erling Smørgrav if (dup2(ttyfd, 0) < 0) 600af12a3e7SDag-Erling Smørgrav error("dup2 stdin: %s", strerror(errno)); 601af12a3e7SDag-Erling Smørgrav if (dup2(ttyfd, 1) < 0) 602af12a3e7SDag-Erling Smørgrav error("dup2 stdout: %s", strerror(errno)); 603af12a3e7SDag-Erling Smørgrav if (dup2(ttyfd, 2) < 0) 604af12a3e7SDag-Erling Smørgrav error("dup2 stderr: %s", strerror(errno)); 605a04a10f8SKris Kennaway 606a04a10f8SKris Kennaway /* Close the extra descriptor for the pseudo tty. */ 607a04a10f8SKris Kennaway close(ttyfd); 608a04a10f8SKris Kennaway 609c2d3a559SKris Kennaway /* record login, etc. similar to login(1) */ 610989dd127SDag-Erling Smørgrav #ifndef HAVE_OSF_SIA 611ca3176e7SBrian Feldman if (!(options.use_login && command == NULL)) 612ca3176e7SBrian Feldman do_login(s, command); 613989dd127SDag-Erling Smørgrav # ifdef LOGIN_NEEDS_UTMPX 614989dd127SDag-Erling Smørgrav else 615989dd127SDag-Erling Smørgrav do_pre_login(s); 616989dd127SDag-Erling Smørgrav # endif 617989dd127SDag-Erling Smørgrav #endif 618e8aafc91SKris Kennaway 619a04a10f8SKris Kennaway /* Do common processing for the child, such as execing the command. */ 620ca3176e7SBrian Feldman do_child(s, command); 621a04a10f8SKris Kennaway /* NOTREACHED */ 622a04a10f8SKris Kennaway } 623989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN 624989dd127SDag-Erling Smørgrav if (is_winnt) 625989dd127SDag-Erling Smørgrav cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); 626989dd127SDag-Erling Smørgrav #endif 627a04a10f8SKris Kennaway if (pid < 0) 628a04a10f8SKris Kennaway packet_disconnect("fork failed: %.100s", strerror(errno)); 629a04a10f8SKris Kennaway s->pid = pid; 630a04a10f8SKris Kennaway 631a04a10f8SKris Kennaway /* Parent. Close the slave side of the pseudo tty. */ 632a04a10f8SKris Kennaway close(ttyfd); 633a04a10f8SKris Kennaway 634a04a10f8SKris Kennaway /* 635a04a10f8SKris Kennaway * Create another descriptor of the pty master side for use as the 636a04a10f8SKris Kennaway * standard input. We could use the original descriptor, but this 637a04a10f8SKris Kennaway * simplifies code in server_loop. The descriptor is bidirectional. 638a04a10f8SKris Kennaway */ 639a04a10f8SKris Kennaway fdout = dup(ptyfd); 640a04a10f8SKris Kennaway if (fdout < 0) 641a04a10f8SKris Kennaway packet_disconnect("dup #1 failed: %.100s", strerror(errno)); 642a04a10f8SKris Kennaway 643a04a10f8SKris Kennaway /* we keep a reference to the pty master */ 644a04a10f8SKris Kennaway ptymaster = dup(ptyfd); 645a04a10f8SKris Kennaway if (ptymaster < 0) 646a04a10f8SKris Kennaway packet_disconnect("dup #2 failed: %.100s", strerror(errno)); 647a04a10f8SKris Kennaway s->ptymaster = ptymaster; 648a04a10f8SKris Kennaway 649a04a10f8SKris Kennaway /* Enter interactive session. */ 650ca3176e7SBrian Feldman packet_set_interactive(1); 651a04a10f8SKris Kennaway if (compat20) { 652a04a10f8SKris Kennaway session_set_fds(s, ptyfd, fdout, -1); 653a04a10f8SKris Kennaway } else { 654a04a10f8SKris Kennaway server_loop(pid, ptyfd, fdout, -1); 655a04a10f8SKris Kennaway /* server_loop _has_ closed ptyfd and fdout. */ 656a04a10f8SKris Kennaway } 657a04a10f8SKris Kennaway } 658a04a10f8SKris Kennaway 659989dd127SDag-Erling Smørgrav #ifdef LOGIN_NEEDS_UTMPX 660989dd127SDag-Erling Smørgrav static void 661989dd127SDag-Erling Smørgrav do_pre_login(Session *s) 662989dd127SDag-Erling Smørgrav { 663989dd127SDag-Erling Smørgrav socklen_t fromlen; 664989dd127SDag-Erling Smørgrav struct sockaddr_storage from; 665989dd127SDag-Erling Smørgrav pid_t pid = getpid(); 666989dd127SDag-Erling Smørgrav 667989dd127SDag-Erling Smørgrav /* 668989dd127SDag-Erling Smørgrav * Get IP address of client. If the connection is not a socket, let 669989dd127SDag-Erling Smørgrav * the address be 0.0.0.0. 670989dd127SDag-Erling Smørgrav */ 671989dd127SDag-Erling Smørgrav memset(&from, 0, sizeof(from)); 672989dd127SDag-Erling Smørgrav if (packet_connection_is_on_socket()) { 673989dd127SDag-Erling Smørgrav fromlen = sizeof(from); 674989dd127SDag-Erling Smørgrav if (getpeername(packet_get_connection_in(), 675989dd127SDag-Erling Smørgrav (struct sockaddr *) & from, &fromlen) < 0) { 676989dd127SDag-Erling Smørgrav debug("getpeername: %.100s", strerror(errno)); 677989dd127SDag-Erling Smørgrav fatal_cleanup(); 678989dd127SDag-Erling Smørgrav } 679989dd127SDag-Erling Smørgrav } 680989dd127SDag-Erling Smørgrav 681989dd127SDag-Erling Smørgrav record_utmp_only(pid, s->tty, s->pw->pw_name, 682989dd127SDag-Erling Smørgrav get_remote_name_or_ip(utmp_len, options.verify_reverse_mapping), 683989dd127SDag-Erling Smørgrav (struct sockaddr *)&from); 684989dd127SDag-Erling Smørgrav } 685989dd127SDag-Erling Smørgrav #endif 686989dd127SDag-Erling Smørgrav 687af12a3e7SDag-Erling Smørgrav /* 688af12a3e7SDag-Erling Smørgrav * This is called to fork and execute a command. If another command is 689af12a3e7SDag-Erling Smørgrav * to be forced, execute that instead. 690af12a3e7SDag-Erling Smørgrav */ 691af12a3e7SDag-Erling Smørgrav void 692af12a3e7SDag-Erling Smørgrav do_exec(Session *s, const char *command) 693af12a3e7SDag-Erling Smørgrav { 694af12a3e7SDag-Erling Smørgrav if (forced_command) { 695af12a3e7SDag-Erling Smørgrav original_command = command; 696af12a3e7SDag-Erling Smørgrav command = forced_command; 697af12a3e7SDag-Erling Smørgrav debug("Forced command '%.900s'", command); 698af12a3e7SDag-Erling Smørgrav } 699af12a3e7SDag-Erling Smørgrav 700af12a3e7SDag-Erling Smørgrav if (s->ttyfd != -1) 701af12a3e7SDag-Erling Smørgrav do_exec_pty(s, command); 702af12a3e7SDag-Erling Smørgrav else 703af12a3e7SDag-Erling Smørgrav do_exec_no_pty(s, command); 704af12a3e7SDag-Erling Smørgrav 705af12a3e7SDag-Erling Smørgrav original_command = NULL; 706af12a3e7SDag-Erling Smørgrav } 707af12a3e7SDag-Erling Smørgrav 708af12a3e7SDag-Erling Smørgrav 709c2d3a559SKris Kennaway /* administrative, login(1)-like work */ 710ca3176e7SBrian Feldman void 711c2d3a559SKris Kennaway do_login(Session *s, const char *command) 712c2d3a559SKris Kennaway { 7136e8ced7fSDag-Erling Smørgrav char *time_string; 714c2d3a559SKris Kennaway socklen_t fromlen; 715c2d3a559SKris Kennaway struct sockaddr_storage from; 716c2d3a559SKris Kennaway struct passwd * pw = s->pw; 717c2d3a559SKris Kennaway pid_t pid = getpid(); 718c2d3a559SKris Kennaway 719c2d3a559SKris Kennaway /* 720c2d3a559SKris Kennaway * Get IP address of client. If the connection is not a socket, let 721c2d3a559SKris Kennaway * the address be 0.0.0.0. 722c2d3a559SKris Kennaway */ 723c2d3a559SKris Kennaway memset(&from, 0, sizeof(from)); 724c2d3a559SKris Kennaway if (packet_connection_is_on_socket()) { 725c2d3a559SKris Kennaway fromlen = sizeof(from); 726c2d3a559SKris Kennaway if (getpeername(packet_get_connection_in(), 727c2d3a559SKris Kennaway (struct sockaddr *) & from, &fromlen) < 0) { 728c2d3a559SKris Kennaway debug("getpeername: %.100s", strerror(errno)); 729c2d3a559SKris Kennaway fatal_cleanup(); 730c2d3a559SKris Kennaway } 731c2d3a559SKris Kennaway } 732c2d3a559SKris Kennaway 73380628bacSDag-Erling Smørgrav /* Record that there was a login on that tty from the remote host. */ 73480628bacSDag-Erling Smørgrav if (!use_privsep) 73580628bacSDag-Erling Smørgrav record_login(pid, s->tty, pw->pw_name, pw->pw_uid, 73680628bacSDag-Erling Smørgrav get_remote_name_or_ip(utmp_len, 73780628bacSDag-Erling Smørgrav options.verify_reverse_mapping), 73880628bacSDag-Erling Smørgrav (struct sockaddr *)&from); 73980628bacSDag-Erling Smørgrav 740098de0c1SAndrey A. Chernov #ifdef USE_PAM 741c2d3a559SKris Kennaway /* 742989dd127SDag-Erling Smørgrav * If password change is needed, do it now. 743989dd127SDag-Erling Smørgrav * This needs to occur before the ~/.hushlogin check. 744c2d3a559SKris Kennaway */ 745989dd127SDag-Erling Smørgrav if (is_pam_password_change_required()) { 746989dd127SDag-Erling Smørgrav print_pam_messages(); 747989dd127SDag-Erling Smørgrav do_pam_chauthtok(); 748989dd127SDag-Erling Smørgrav } 749989dd127SDag-Erling Smørgrav #endif 750af12a3e7SDag-Erling Smørgrav 751989dd127SDag-Erling Smørgrav if (check_quietlogin(s, command)) 752989dd127SDag-Erling Smørgrav return; 753989dd127SDag-Erling Smørgrav 754989dd127SDag-Erling Smørgrav #ifdef USE_PAM 755989dd127SDag-Erling Smørgrav if (!is_pam_password_change_required()) 756989dd127SDag-Erling Smørgrav print_pam_messages(); 757989dd127SDag-Erling Smørgrav #endif /* USE_PAM */ 758989dd127SDag-Erling Smørgrav #ifdef WITH_AIXAUTHENTICATE 759989dd127SDag-Erling Smørgrav if (aixloginmsg && *aixloginmsg) 760989dd127SDag-Erling Smørgrav printf("%s\n", aixloginmsg); 761989dd127SDag-Erling Smørgrav #endif /* WITH_AIXAUTHENTICATE */ 762989dd127SDag-Erling Smørgrav 763989dd127SDag-Erling Smørgrav if (options.print_lastlog && s->last_login_time != 0) { 76480628bacSDag-Erling Smørgrav time_string = ctime(&s->last_login_time); 765c2d3a559SKris Kennaway if (strchr(time_string, '\n')) 766c2d3a559SKris Kennaway *strchr(time_string, '\n') = 0; 76780628bacSDag-Erling Smørgrav if (strcmp(s->hostname, "") == 0) 768c2d3a559SKris Kennaway printf("Last login: %s\r\n", time_string); 769c2d3a559SKris Kennaway else 77080628bacSDag-Erling Smørgrav printf("Last login: %s from %s\r\n", time_string, 77180628bacSDag-Erling Smørgrav s->hostname); 772c2d3a559SKris Kennaway } 773c2d3a559SKris Kennaway 774ca3176e7SBrian Feldman do_motd(); 775ca3176e7SBrian Feldman } 776ca3176e7SBrian Feldman 777ca3176e7SBrian Feldman /* 778ca3176e7SBrian Feldman * Display the message of the day. 779ca3176e7SBrian Feldman */ 780ca3176e7SBrian Feldman void 781ca3176e7SBrian Feldman do_motd(void) 782ca3176e7SBrian Feldman { 783ca3176e7SBrian Feldman FILE *f; 784ca3176e7SBrian Feldman char buf[256]; 785ca3176e7SBrian Feldman 786ca3176e7SBrian Feldman if (options.print_motd) { 787c2d3a559SKris Kennaway #ifdef HAVE_LOGIN_CAP 788c2d3a559SKris Kennaway f = fopen(login_getcapstr(lc, "welcome", "/etc/motd", 789c2d3a559SKris Kennaway "/etc/motd"), "r"); 790af12a3e7SDag-Erling Smørgrav #else 791c2d3a559SKris Kennaway f = fopen("/etc/motd", "r"); 792af12a3e7SDag-Erling Smørgrav #endif 793c2d3a559SKris Kennaway if (f) { 794c2d3a559SKris Kennaway while (fgets(buf, sizeof(buf), f)) 795c2d3a559SKris Kennaway fputs(buf, stdout); 796c2d3a559SKris Kennaway fclose(f); 797c2d3a559SKris Kennaway } 798c2d3a559SKris Kennaway } 799ca3176e7SBrian Feldman } 800c2d3a559SKris Kennaway 801af12a3e7SDag-Erling Smørgrav 802ca3176e7SBrian Feldman /* 803ca3176e7SBrian Feldman * Check for quiet login, either .hushlogin or command given. 804ca3176e7SBrian Feldman */ 805ca3176e7SBrian Feldman int 806ca3176e7SBrian Feldman check_quietlogin(Session *s, const char *command) 807ca3176e7SBrian Feldman { 808ca3176e7SBrian Feldman char buf[256]; 809ca3176e7SBrian Feldman struct passwd *pw = s->pw; 810ca3176e7SBrian Feldman struct stat st; 811ca3176e7SBrian Feldman 812ca3176e7SBrian Feldman /* Return 1 if .hushlogin exists or a command given. */ 813ca3176e7SBrian Feldman if (command != NULL) 814ca3176e7SBrian Feldman return 1; 815ca3176e7SBrian Feldman snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir); 816c2d3a559SKris Kennaway #ifdef HAVE_LOGIN_CAP 817ca3176e7SBrian Feldman if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0) 818ca3176e7SBrian Feldman return 1; 819ca3176e7SBrian Feldman #else 820ca3176e7SBrian Feldman if (stat(buf, &st) >= 0) 821ca3176e7SBrian Feldman return 1; 822ca3176e7SBrian Feldman #endif 823ca3176e7SBrian Feldman return 0; 824c2d3a559SKris Kennaway } 825c2d3a559SKris Kennaway 826a04a10f8SKris Kennaway /* 827a04a10f8SKris Kennaway * Sets the value of the given variable in the environment. If the variable 828a04a10f8SKris Kennaway * already exists, its value is overriden. 829a04a10f8SKris Kennaway */ 830af12a3e7SDag-Erling Smørgrav static void 831ca3176e7SBrian Feldman child_set_env(char ***envp, u_int *envsizep, const char *name, 832a04a10f8SKris Kennaway const char *value) 833a04a10f8SKris Kennaway { 834ca3176e7SBrian Feldman u_int i, namelen; 835a04a10f8SKris Kennaway char **env; 836a04a10f8SKris Kennaway 837a04a10f8SKris Kennaway /* 838a04a10f8SKris Kennaway * Find the slot where the value should be stored. If the variable 839a04a10f8SKris Kennaway * already exists, we reuse the slot; otherwise we append a new slot 840a04a10f8SKris Kennaway * at the end of the array, expanding if necessary. 841a04a10f8SKris Kennaway */ 842a04a10f8SKris Kennaway env = *envp; 843a04a10f8SKris Kennaway namelen = strlen(name); 844a04a10f8SKris Kennaway for (i = 0; env[i]; i++) 845a04a10f8SKris Kennaway if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=') 846a04a10f8SKris Kennaway break; 847a04a10f8SKris Kennaway if (env[i]) { 848a04a10f8SKris Kennaway /* Reuse the slot. */ 849a04a10f8SKris Kennaway xfree(env[i]); 850a04a10f8SKris Kennaway } else { 851a04a10f8SKris Kennaway /* New variable. Expand if necessary. */ 852a04a10f8SKris Kennaway if (i >= (*envsizep) - 1) { 853a82e551fSDag-Erling Smørgrav if (*envsizep >= 1000) 854a82e551fSDag-Erling Smørgrav fatal("child_set_env: too many env vars," 855a82e551fSDag-Erling Smørgrav " skipping: %.100s", name); 856a04a10f8SKris Kennaway (*envsizep) += 50; 857a04a10f8SKris Kennaway env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *)); 858a04a10f8SKris Kennaway } 859a04a10f8SKris Kennaway /* Need to set the NULL pointer at end of array beyond the new slot. */ 860a04a10f8SKris Kennaway env[i + 1] = NULL; 861a04a10f8SKris Kennaway } 862a04a10f8SKris Kennaway 863a04a10f8SKris Kennaway /* Allocate space and format the variable in the appropriate slot. */ 864a04a10f8SKris Kennaway env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1); 865a04a10f8SKris Kennaway snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value); 866a04a10f8SKris Kennaway } 867a04a10f8SKris Kennaway 868a04a10f8SKris Kennaway /* 869a04a10f8SKris Kennaway * Reads environment variables from the given file and adds/overrides them 870a04a10f8SKris Kennaway * into the environment. If the file does not exist, this does nothing. 871a04a10f8SKris Kennaway * Otherwise, it must consist of empty lines, comments (line starts with '#') 872a04a10f8SKris Kennaway * and assignments of the form name=value. No other forms are allowed. 873a04a10f8SKris Kennaway */ 874af12a3e7SDag-Erling Smørgrav static void 875ca3176e7SBrian Feldman read_environment_file(char ***env, u_int *envsize, 876a04a10f8SKris Kennaway const char *filename) 877a04a10f8SKris Kennaway { 878a04a10f8SKris Kennaway FILE *f; 879a04a10f8SKris Kennaway char buf[4096]; 880a04a10f8SKris Kennaway char *cp, *value; 881a82e551fSDag-Erling Smørgrav u_int lineno = 0; 882a04a10f8SKris Kennaway 883a04a10f8SKris Kennaway f = fopen(filename, "r"); 884a04a10f8SKris Kennaway if (!f) 885a04a10f8SKris Kennaway return; 886a04a10f8SKris Kennaway 887a04a10f8SKris Kennaway while (fgets(buf, sizeof(buf), f)) { 888a82e551fSDag-Erling Smørgrav if (++lineno > 1000) 889a82e551fSDag-Erling Smørgrav fatal("Too many lines in environment file %s", filename); 890a04a10f8SKris Kennaway for (cp = buf; *cp == ' ' || *cp == '\t'; cp++) 891a04a10f8SKris Kennaway ; 892a04a10f8SKris Kennaway if (!*cp || *cp == '#' || *cp == '\n') 893a04a10f8SKris Kennaway continue; 894a04a10f8SKris Kennaway if (strchr(cp, '\n')) 895a04a10f8SKris Kennaway *strchr(cp, '\n') = '\0'; 896a04a10f8SKris Kennaway value = strchr(cp, '='); 897a04a10f8SKris Kennaway if (value == NULL) { 898a82e551fSDag-Erling Smørgrav fprintf(stderr, "Bad line %u in %.100s\n", lineno, 899a82e551fSDag-Erling Smørgrav filename); 900a04a10f8SKris Kennaway continue; 901a04a10f8SKris Kennaway } 902db1cb46cSKris Kennaway /* 903db1cb46cSKris Kennaway * Replace the equals sign by nul, and advance value to 904db1cb46cSKris Kennaway * the value string. 905db1cb46cSKris Kennaway */ 906a04a10f8SKris Kennaway *value = '\0'; 907a04a10f8SKris Kennaway value++; 908a04a10f8SKris Kennaway child_set_env(env, envsize, cp, value); 909a04a10f8SKris Kennaway } 910a04a10f8SKris Kennaway fclose(f); 911a04a10f8SKris Kennaway } 912a04a10f8SKris Kennaway 913989dd127SDag-Erling Smørgrav void copy_environment(char **source, char ***env, u_int *envsize) 91409958426SBrian Feldman { 915989dd127SDag-Erling Smørgrav char *var_name, *var_val; 91609958426SBrian Feldman int i; 91709958426SBrian Feldman 918989dd127SDag-Erling Smørgrav if (source == NULL) 91909958426SBrian Feldman return; 92009958426SBrian Feldman 921989dd127SDag-Erling Smørgrav for(i = 0; source[i] != NULL; i++) { 922989dd127SDag-Erling Smørgrav var_name = xstrdup(source[i]); 923989dd127SDag-Erling Smørgrav if ((var_val = strstr(var_name, "=")) == NULL) { 924989dd127SDag-Erling Smørgrav xfree(var_name); 92509958426SBrian Feldman continue; 926989dd127SDag-Erling Smørgrav } 927989dd127SDag-Erling Smørgrav *var_val++ = '\0'; 92809958426SBrian Feldman 929989dd127SDag-Erling Smørgrav debug3("Copy environment: %s=%s", var_name, var_val); 93009958426SBrian Feldman child_set_env(env, envsize, var_name, var_val); 931989dd127SDag-Erling Smørgrav 932989dd127SDag-Erling Smørgrav xfree(var_name); 93309958426SBrian Feldman } 93409958426SBrian Feldman } 93509958426SBrian Feldman 936af12a3e7SDag-Erling Smørgrav static char ** 937989dd127SDag-Erling Smørgrav do_setup_env(Session *s, const char *shell) 938a04a10f8SKris Kennaway { 939a04a10f8SKris Kennaway char buf[256]; 940af12a3e7SDag-Erling Smørgrav u_int i, envsize; 941989dd127SDag-Erling Smørgrav char **env; 942c62005fcSDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP 943c62005fcSDag-Erling Smørgrav extern char **environ; 944c62005fcSDag-Erling Smørgrav char **senv, **var; 945c62005fcSDag-Erling Smørgrav #endif 946af12a3e7SDag-Erling Smørgrav struct passwd *pw = s->pw; 947a04a10f8SKris Kennaway 948a04a10f8SKris Kennaway /* Initialize the environment. */ 949a04a10f8SKris Kennaway envsize = 100; 950a04a10f8SKris Kennaway env = xmalloc(envsize * sizeof(char *)); 951a04a10f8SKris Kennaway env[0] = NULL; 952989dd127SDag-Erling Smørgrav 953989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN 954989dd127SDag-Erling Smørgrav /* 955989dd127SDag-Erling Smørgrav * The Windows environment contains some setting which are 956989dd127SDag-Erling Smørgrav * important for a running system. They must not be dropped. 957989dd127SDag-Erling Smørgrav */ 958989dd127SDag-Erling Smørgrav copy_environment(environ, &env, &envsize); 959989dd127SDag-Erling Smørgrav #endif 960a04a10f8SKris Kennaway 961c62005fcSDag-Erling Smørgrav if (getenv("TZ")) 962c62005fcSDag-Erling Smørgrav child_set_env(&env, &envsize, "TZ", getenv("TZ")); 963a04a10f8SKris Kennaway if (!options.use_login) { 964a04a10f8SKris Kennaway /* Set basic environment. */ 965a04a10f8SKris Kennaway child_set_env(&env, &envsize, "USER", pw->pw_name); 966a04a10f8SKris Kennaway child_set_env(&env, &envsize, "LOGNAME", pw->pw_name); 967a04a10f8SKris Kennaway child_set_env(&env, &envsize, "HOME", pw->pw_dir); 968c62005fcSDag-Erling Smørgrav snprintf(buf, sizeof buf, "%.200s/%.50s", 969c62005fcSDag-Erling Smørgrav _PATH_MAILDIR, pw->pw_name); 970c62005fcSDag-Erling Smørgrav child_set_env(&env, &envsize, "MAIL", buf); 971989dd127SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP 972c62005fcSDag-Erling Smørgrav child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); 973c62005fcSDag-Erling Smørgrav child_set_env(&env, &envsize, "TERM", "su"); 974c62005fcSDag-Erling Smørgrav senv = environ; 975c62005fcSDag-Erling Smørgrav environ = xmalloc(sizeof(char *)); 976c62005fcSDag-Erling Smørgrav *environ = NULL; 977c62005fcSDag-Erling Smørgrav (void) setusercontext(lc, pw, pw->pw_uid, 978c62005fcSDag-Erling Smørgrav LOGIN_SETENV|LOGIN_SETPATH); 979c62005fcSDag-Erling Smørgrav copy_environment(environ, &env, &envsize); 980c62005fcSDag-Erling Smørgrav for (var = environ; *var != NULL; ++var) 981c62005fcSDag-Erling Smørgrav xfree(*var); 982c62005fcSDag-Erling Smørgrav xfree(environ); 983c62005fcSDag-Erling Smørgrav environ = senv; 984989dd127SDag-Erling Smørgrav #else /* HAVE_LOGIN_CAP */ 985989dd127SDag-Erling Smørgrav # ifndef HAVE_CYGWIN 986989dd127SDag-Erling Smørgrav /* 987989dd127SDag-Erling Smørgrav * There's no standard path on Windows. The path contains 988989dd127SDag-Erling Smørgrav * important components pointing to the system directories, 989989dd127SDag-Erling Smørgrav * needed for loading shared libraries. So the path better 990989dd127SDag-Erling Smørgrav * remains intact here. 991989dd127SDag-Erling Smørgrav */ 992989dd127SDag-Erling Smørgrav # ifdef SUPERUSER_PATH 993989dd127SDag-Erling Smørgrav child_set_env(&env, &envsize, "PATH", 994989dd127SDag-Erling Smørgrav s->pw->pw_uid == 0 ? SUPERUSER_PATH : _PATH_STDPATH); 995989dd127SDag-Erling Smørgrav # else 996a04a10f8SKris Kennaway child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); 997989dd127SDag-Erling Smørgrav # endif /* SUPERUSER_PATH */ 998989dd127SDag-Erling Smørgrav # endif /* HAVE_CYGWIN */ 999989dd127SDag-Erling Smørgrav #endif /* HAVE_LOGIN_CAP */ 1000a04a10f8SKris Kennaway 1001a04a10f8SKris Kennaway /* Normal systems set SHELL by default. */ 1002a04a10f8SKris Kennaway child_set_env(&env, &envsize, "SHELL", shell); 1003a04a10f8SKris Kennaway } 1004a04a10f8SKris Kennaway 1005a04a10f8SKris Kennaway /* Set custom environment options from RSA authentication. */ 10061c5093bbSJacques Vidrine if (!options.use_login) { 1007a04a10f8SKris Kennaway while (custom_environment) { 1008a04a10f8SKris Kennaway struct envstring *ce = custom_environment; 1009a04a10f8SKris Kennaway char *s = ce->s; 1010af12a3e7SDag-Erling Smørgrav 1011af12a3e7SDag-Erling Smørgrav for (i = 0; s[i] != '=' && s[i]; i++) 1012af12a3e7SDag-Erling Smørgrav ; 1013a04a10f8SKris Kennaway if (s[i] == '=') { 1014a04a10f8SKris Kennaway s[i] = 0; 1015a04a10f8SKris Kennaway child_set_env(&env, &envsize, s, s + i + 1); 1016a04a10f8SKris Kennaway } 1017a04a10f8SKris Kennaway custom_environment = ce->next; 1018a04a10f8SKris Kennaway xfree(ce->s); 1019a04a10f8SKris Kennaway xfree(ce); 1020a04a10f8SKris Kennaway } 10211c5093bbSJacques Vidrine } 1022a04a10f8SKris Kennaway 1023a04a10f8SKris Kennaway snprintf(buf, sizeof buf, "%.50s %d %d", 1024a04a10f8SKris Kennaway get_remote_ipaddr(), get_remote_port(), get_local_port()); 1025a04a10f8SKris Kennaway child_set_env(&env, &envsize, "SSH_CLIENT", buf); 1026a04a10f8SKris Kennaway 1027ca3176e7SBrian Feldman if (s->ttyfd != -1) 1028ca3176e7SBrian Feldman child_set_env(&env, &envsize, "SSH_TTY", s->tty); 1029ca3176e7SBrian Feldman if (s->term) 1030ca3176e7SBrian Feldman child_set_env(&env, &envsize, "TERM", s->term); 1031ca3176e7SBrian Feldman if (s->display) 1032ca3176e7SBrian Feldman child_set_env(&env, &envsize, "DISPLAY", s->display); 1033c2d3a559SKris Kennaway if (original_command) 1034c2d3a559SKris Kennaway child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND", 1035c2d3a559SKris Kennaway original_command); 1036989dd127SDag-Erling Smørgrav 1037989dd127SDag-Erling Smørgrav #ifdef _AIX 1038989dd127SDag-Erling Smørgrav { 1039989dd127SDag-Erling Smørgrav char *cp; 1040989dd127SDag-Erling Smørgrav 1041989dd127SDag-Erling Smørgrav if ((cp = getenv("AUTHSTATE")) != NULL) 1042989dd127SDag-Erling Smørgrav child_set_env(&env, &envsize, "AUTHSTATE", cp); 1043989dd127SDag-Erling Smørgrav if ((cp = getenv("KRB5CCNAME")) != NULL) 1044989dd127SDag-Erling Smørgrav child_set_env(&env, &envsize, "KRB5CCNAME", cp); 1045989dd127SDag-Erling Smørgrav read_environment_file(&env, &envsize, "/etc/environment"); 1046989dd127SDag-Erling Smørgrav } 1047989dd127SDag-Erling Smørgrav #endif 1048a04a10f8SKris Kennaway #ifdef KRB4 1049af12a3e7SDag-Erling Smørgrav if (s->authctxt->krb4_ticket_file) 1050af12a3e7SDag-Erling Smørgrav child_set_env(&env, &envsize, "KRBTKFILE", 1051af12a3e7SDag-Erling Smørgrav s->authctxt->krb4_ticket_file); 1052af12a3e7SDag-Erling Smørgrav #endif 1053e8aafc91SKris Kennaway #ifdef KRB5 1054af12a3e7SDag-Erling Smørgrav if (s->authctxt->krb5_ticket_file) 1055af12a3e7SDag-Erling Smørgrav child_set_env(&env, &envsize, "KRB5CCNAME", 1056af12a3e7SDag-Erling Smørgrav s->authctxt->krb5_ticket_file); 1057af12a3e7SDag-Erling Smørgrav #endif 105809958426SBrian Feldman #ifdef USE_PAM 105909958426SBrian Feldman /* Pull in any environment variables that may have been set by PAM. */ 1060989dd127SDag-Erling Smørgrav copy_environment(fetch_pam_environment(), &env, &envsize); 106109958426SBrian Feldman #endif /* USE_PAM */ 106209958426SBrian Feldman 106380628bacSDag-Erling Smørgrav if (auth_sock_name != NULL) 1064a04a10f8SKris Kennaway child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, 106580628bacSDag-Erling Smørgrav auth_sock_name); 1066a04a10f8SKris Kennaway 1067a04a10f8SKris Kennaway /* read $HOME/.ssh/environment. */ 1068a04a10f8SKris Kennaway if (!options.use_login) { 1069db1cb46cSKris Kennaway snprintf(buf, sizeof buf, "%.200s/.ssh/environment", 1070db1cb46cSKris Kennaway pw->pw_dir); 1071a04a10f8SKris Kennaway read_environment_file(&env, &envsize, buf); 1072a04a10f8SKris Kennaway } 1073a04a10f8SKris Kennaway if (debug_flag) { 1074a04a10f8SKris Kennaway /* dump the environment */ 1075a04a10f8SKris Kennaway fprintf(stderr, "Environment:\n"); 1076a04a10f8SKris Kennaway for (i = 0; env[i]; i++) 1077a04a10f8SKris Kennaway fprintf(stderr, " %.200s\n", env[i]); 1078a04a10f8SKris Kennaway } 1079af12a3e7SDag-Erling Smørgrav return env; 1080e8aafc91SKris Kennaway } 1081ca3176e7SBrian Feldman 1082ca3176e7SBrian Feldman /* 1083af12a3e7SDag-Erling Smørgrav * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found 1084af12a3e7SDag-Erling Smørgrav * first in this order). 1085ca3176e7SBrian Feldman */ 1086af12a3e7SDag-Erling Smørgrav static void 1087af12a3e7SDag-Erling Smørgrav do_rc_files(Session *s, const char *shell) 1088af12a3e7SDag-Erling Smørgrav { 1089af12a3e7SDag-Erling Smørgrav FILE *f = NULL; 1090af12a3e7SDag-Erling Smørgrav char cmd[1024]; 1091af12a3e7SDag-Erling Smørgrav int do_xauth; 1092af12a3e7SDag-Erling Smørgrav struct stat st; 1093a04a10f8SKris Kennaway 1094af12a3e7SDag-Erling Smørgrav do_xauth = 1095af12a3e7SDag-Erling Smørgrav s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL; 1096a04a10f8SKris Kennaway 1097ca3176e7SBrian Feldman /* ignore _PATH_SSH_USER_RC for subsystems */ 1098ca3176e7SBrian Feldman if (!s->is_subsystem && (stat(_PATH_SSH_USER_RC, &st) >= 0)) { 1099e9fd63dfSBrian Feldman snprintf(cmd, sizeof cmd, "%s -c '%s %s'", 1100e9fd63dfSBrian Feldman shell, _PATH_BSHELL, _PATH_SSH_USER_RC); 1101a04a10f8SKris Kennaway if (debug_flag) 1102e9fd63dfSBrian Feldman fprintf(stderr, "Running %s\n", cmd); 1103e9fd63dfSBrian Feldman f = popen(cmd, "w"); 1104a04a10f8SKris Kennaway if (f) { 1105ca3176e7SBrian Feldman if (do_xauth) 1106ca3176e7SBrian Feldman fprintf(f, "%s %s\n", s->auth_proto, 1107ca3176e7SBrian Feldman s->auth_data); 1108a04a10f8SKris Kennaway pclose(f); 1109a04a10f8SKris Kennaway } else 1110ca3176e7SBrian Feldman fprintf(stderr, "Could not run %s\n", 1111ca3176e7SBrian Feldman _PATH_SSH_USER_RC); 1112ca3176e7SBrian Feldman } else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) { 1113a04a10f8SKris Kennaway if (debug_flag) 1114ca3176e7SBrian Feldman fprintf(stderr, "Running %s %s\n", _PATH_BSHELL, 1115ca3176e7SBrian Feldman _PATH_SSH_SYSTEM_RC); 1116ca3176e7SBrian Feldman f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w"); 1117a04a10f8SKris Kennaway if (f) { 1118ca3176e7SBrian Feldman if (do_xauth) 1119ca3176e7SBrian Feldman fprintf(f, "%s %s\n", s->auth_proto, 1120ca3176e7SBrian Feldman s->auth_data); 1121a04a10f8SKris Kennaway pclose(f); 1122a04a10f8SKris Kennaway } else 1123ca3176e7SBrian Feldman fprintf(stderr, "Could not run %s\n", 1124ca3176e7SBrian Feldman _PATH_SSH_SYSTEM_RC); 1125ca3176e7SBrian Feldman } else if (do_xauth && options.xauth_location != NULL) { 1126a04a10f8SKris Kennaway /* Add authority data to .Xauthority if appropriate. */ 1127db1cb46cSKris Kennaway if (debug_flag) { 1128db1cb46cSKris Kennaway fprintf(stderr, 112980628bacSDag-Erling Smørgrav "Running %.500s add " 1130ca3176e7SBrian Feldman "%.100s %.100s %.100s\n", 1131af12a3e7SDag-Erling Smørgrav options.xauth_location, s->auth_display, 1132ca3176e7SBrian Feldman s->auth_proto, s->auth_data); 1133db1cb46cSKris Kennaway } 1134c2d3a559SKris Kennaway snprintf(cmd, sizeof cmd, "%s -q -", 1135c2d3a559SKris Kennaway options.xauth_location); 1136c2d3a559SKris Kennaway f = popen(cmd, "w"); 1137a04a10f8SKris Kennaway if (f) { 1138af12a3e7SDag-Erling Smørgrav fprintf(f, "add %s %s %s\n", 1139af12a3e7SDag-Erling Smørgrav s->auth_display, s->auth_proto, 1140ca3176e7SBrian Feldman s->auth_data); 1141a04a10f8SKris Kennaway pclose(f); 1142c2d3a559SKris Kennaway } else { 1143c2d3a559SKris Kennaway fprintf(stderr, "Could not run %s\n", 1144c2d3a559SKris Kennaway cmd); 1145a04a10f8SKris Kennaway } 1146a04a10f8SKris Kennaway } 1147a04a10f8SKris Kennaway } 1148ca3176e7SBrian Feldman 1149af12a3e7SDag-Erling Smørgrav static void 1150af12a3e7SDag-Erling Smørgrav do_nologin(struct passwd *pw) 1151af12a3e7SDag-Erling Smørgrav { 1152af12a3e7SDag-Erling Smørgrav FILE *f = NULL; 1153af12a3e7SDag-Erling Smørgrav char buf[1024]; 1154af12a3e7SDag-Erling Smørgrav 1155af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP 1156af12a3e7SDag-Erling Smørgrav if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid) 1157af12a3e7SDag-Erling Smørgrav f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN, 1158af12a3e7SDag-Erling Smørgrav _PATH_NOLOGIN), "r"); 1159af12a3e7SDag-Erling Smørgrav #else 1160af12a3e7SDag-Erling Smørgrav if (pw->pw_uid) 1161af12a3e7SDag-Erling Smørgrav f = fopen(_PATH_NOLOGIN, "r"); 1162af12a3e7SDag-Erling Smørgrav #endif 1163af12a3e7SDag-Erling Smørgrav if (f) { 1164af12a3e7SDag-Erling Smørgrav /* /etc/nologin exists. Print its contents and exit. */ 1165af12a3e7SDag-Erling Smørgrav while (fgets(buf, sizeof(buf), f)) 1166af12a3e7SDag-Erling Smørgrav fputs(buf, stderr); 1167af12a3e7SDag-Erling Smørgrav fclose(f); 1168af12a3e7SDag-Erling Smørgrav exit(254); 1169af12a3e7SDag-Erling Smørgrav } 1170af12a3e7SDag-Erling Smørgrav } 1171af12a3e7SDag-Erling Smørgrav 1172af12a3e7SDag-Erling Smørgrav /* Set login name, uid, gid, and groups. */ 1173989dd127SDag-Erling Smørgrav void 117480628bacSDag-Erling Smørgrav do_setusercontext(struct passwd *pw) 1175af12a3e7SDag-Erling Smørgrav { 1176a82e551fSDag-Erling Smørgrav char tty='\0'; 1177a82e551fSDag-Erling Smørgrav 1178989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN 1179989dd127SDag-Erling Smørgrav if (is_winnt) { 1180989dd127SDag-Erling Smørgrav #else /* HAVE_CYGWIN */ 118103df31a6SAndrey A. Chernov if (getuid() == 0 || geteuid() == 0) { 1182989dd127SDag-Erling Smørgrav #endif /* HAVE_CYGWIN */ 1183989dd127SDag-Erling Smørgrav #ifdef HAVE_SETPCRED 1184989dd127SDag-Erling Smørgrav setpcred(pw->pw_name); 1185989dd127SDag-Erling Smørgrav #endif /* HAVE_SETPCRED */ 1186989dd127SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP 1187a82e551fSDag-Erling Smørgrav #ifdef __bsdi__ 1188a82e551fSDag-Erling Smørgrav setpgid(0, 0); 1189a82e551fSDag-Erling Smørgrav #endif 1190989dd127SDag-Erling Smørgrav if (setusercontext(lc, pw, pw->pw_uid, 1191c62005fcSDag-Erling Smørgrav (LOGIN_SETALL & ~(LOGIN_SETENV|LOGIN_SETPATH))) < 0) { 1192989dd127SDag-Erling Smørgrav perror("unable to set user context"); 1193989dd127SDag-Erling Smørgrav exit(1); 1194989dd127SDag-Erling Smørgrav } 1195989dd127SDag-Erling Smørgrav #else 1196989dd127SDag-Erling Smørgrav # if defined(HAVE_GETLUID) && defined(HAVE_SETLUID) 1197989dd127SDag-Erling Smørgrav /* Sets login uid for accounting */ 1198989dd127SDag-Erling Smørgrav if (getluid() == -1 && setluid(pw->pw_uid) == -1) 1199989dd127SDag-Erling Smørgrav error("setluid: %s", strerror(errno)); 1200989dd127SDag-Erling Smørgrav # endif /* defined(HAVE_GETLUID) && defined(HAVE_SETLUID) */ 1201989dd127SDag-Erling Smørgrav 1202af12a3e7SDag-Erling Smørgrav if (setlogin(pw->pw_name) < 0) 1203af12a3e7SDag-Erling Smørgrav error("setlogin failed: %s", strerror(errno)); 1204af12a3e7SDag-Erling Smørgrav if (setgid(pw->pw_gid) < 0) { 1205af12a3e7SDag-Erling Smørgrav perror("setgid"); 1206af12a3e7SDag-Erling Smørgrav exit(1); 1207af12a3e7SDag-Erling Smørgrav } 1208af12a3e7SDag-Erling Smørgrav /* Initialize the group list. */ 1209af12a3e7SDag-Erling Smørgrav if (initgroups(pw->pw_name, pw->pw_gid) < 0) { 1210af12a3e7SDag-Erling Smørgrav perror("initgroups"); 1211af12a3e7SDag-Erling Smørgrav exit(1); 1212af12a3e7SDag-Erling Smørgrav } 1213af12a3e7SDag-Erling Smørgrav endgrent(); 1214989dd127SDag-Erling Smørgrav # ifdef USE_PAM 1215989dd127SDag-Erling Smørgrav /* 1216989dd127SDag-Erling Smørgrav * PAM credentials may take the form of supplementary groups. 1217989dd127SDag-Erling Smørgrav * These will have been wiped by the above initgroups() call. 1218989dd127SDag-Erling Smørgrav * Reestablish them here. 1219989dd127SDag-Erling Smørgrav */ 1220989dd127SDag-Erling Smørgrav do_pam_setcred(0); 1221989dd127SDag-Erling Smørgrav # endif /* USE_PAM */ 1222989dd127SDag-Erling Smørgrav # if defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) 1223989dd127SDag-Erling Smørgrav irix_setusercontext(pw); 1224989dd127SDag-Erling Smørgrav # endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */ 1225a82e551fSDag-Erling Smørgrav # ifdef _AIX 1226a82e551fSDag-Erling Smørgrav /* XXX: Disable tty setting. Enabled if required later */ 1227a82e551fSDag-Erling Smørgrav aix_usrinfo(pw, &tty, -1); 1228a82e551fSDag-Erling Smørgrav # endif /* _AIX */ 1229af12a3e7SDag-Erling Smørgrav /* Permanently switch to the desired uid. */ 1230af12a3e7SDag-Erling Smørgrav permanently_set_uid(pw); 1231989dd127SDag-Erling Smørgrav #endif 1232af12a3e7SDag-Erling Smørgrav } 1233af12a3e7SDag-Erling Smørgrav if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) 1234af12a3e7SDag-Erling Smørgrav fatal("Failed to set uids to %u.", (u_int) pw->pw_uid); 123580628bacSDag-Erling Smørgrav } 123680628bacSDag-Erling Smørgrav 123780628bacSDag-Erling Smørgrav static void 123880628bacSDag-Erling Smørgrav launch_login(struct passwd *pw, const char *hostname) 123980628bacSDag-Erling Smørgrav { 124080628bacSDag-Erling Smørgrav /* Launch login(1). */ 124180628bacSDag-Erling Smørgrav 1242989dd127SDag-Erling Smørgrav execl(LOGIN_PROGRAM, "login", "-h", hostname, 1243989dd127SDag-Erling Smørgrav #ifdef xxxLOGIN_NEEDS_TERM 1244989dd127SDag-Erling Smørgrav (s->term ? s->term : "unknown"), 1245989dd127SDag-Erling Smørgrav #endif /* LOGIN_NEEDS_TERM */ 1246989dd127SDag-Erling Smørgrav #ifdef LOGIN_NO_ENDOPT 1247989dd127SDag-Erling Smørgrav "-p", "-f", pw->pw_name, (char *)NULL); 1248989dd127SDag-Erling Smørgrav #else 124980628bacSDag-Erling Smørgrav "-p", "-f", "--", pw->pw_name, (char *)NULL); 1250989dd127SDag-Erling Smørgrav #endif 125180628bacSDag-Erling Smørgrav 125280628bacSDag-Erling Smørgrav /* Login couldn't be executed, die. */ 125380628bacSDag-Erling Smørgrav 125480628bacSDag-Erling Smørgrav perror("login"); 125580628bacSDag-Erling Smørgrav exit(1); 1256af12a3e7SDag-Erling Smørgrav } 1257af12a3e7SDag-Erling Smørgrav 1258af12a3e7SDag-Erling Smørgrav /* 1259af12a3e7SDag-Erling Smørgrav * Performs common processing for the child, such as setting up the 1260af12a3e7SDag-Erling Smørgrav * environment, closing extra file descriptors, setting the user and group 1261af12a3e7SDag-Erling Smørgrav * ids, and executing the command or shell. 1262af12a3e7SDag-Erling Smørgrav */ 1263af12a3e7SDag-Erling Smørgrav void 1264af12a3e7SDag-Erling Smørgrav do_child(Session *s, const char *command) 1265af12a3e7SDag-Erling Smørgrav { 1266af12a3e7SDag-Erling Smørgrav extern char **environ; 1267989dd127SDag-Erling Smørgrav char **env; 1268af12a3e7SDag-Erling Smørgrav char *argv[10]; 1269af12a3e7SDag-Erling Smørgrav const char *shell, *shell0, *hostname = NULL; 1270af12a3e7SDag-Erling Smørgrav struct passwd *pw = s->pw; 1271af12a3e7SDag-Erling Smørgrav u_int i; 1272af12a3e7SDag-Erling Smørgrav 1273af12a3e7SDag-Erling Smørgrav /* remove hostkey from the child's memory */ 1274af12a3e7SDag-Erling Smørgrav destroy_sensitive_data(); 1275af12a3e7SDag-Erling Smørgrav 1276af12a3e7SDag-Erling Smørgrav /* login(1) is only called if we execute the login shell */ 1277af12a3e7SDag-Erling Smørgrav if (options.use_login && command != NULL) 1278af12a3e7SDag-Erling Smørgrav options.use_login = 0; 1279af12a3e7SDag-Erling Smørgrav 1280af12a3e7SDag-Erling Smørgrav /* 1281af12a3e7SDag-Erling Smørgrav * Login(1) does this as well, and it needs uid 0 for the "-h" 1282af12a3e7SDag-Erling Smørgrav * switch, so we let login(1) to this for us. 1283af12a3e7SDag-Erling Smørgrav */ 1284af12a3e7SDag-Erling Smørgrav if (!options.use_login) { 1285989dd127SDag-Erling Smørgrav #ifdef HAVE_OSF_SIA 1286989dd127SDag-Erling Smørgrav session_setup_sia(pw->pw_name, s->ttyfd == -1 ? NULL : s->tty); 1287989dd127SDag-Erling Smørgrav if (!check_quietlogin(s, command)) 1288989dd127SDag-Erling Smørgrav do_motd(); 1289989dd127SDag-Erling Smørgrav #else /* HAVE_OSF_SIA */ 1290af12a3e7SDag-Erling Smørgrav do_nologin(pw); 1291989dd127SDag-Erling Smørgrav do_setusercontext(pw); 1292989dd127SDag-Erling Smørgrav #endif /* HAVE_OSF_SIA */ 1293af12a3e7SDag-Erling Smørgrav } 1294af12a3e7SDag-Erling Smørgrav 1295af12a3e7SDag-Erling Smørgrav /* 1296af12a3e7SDag-Erling Smørgrav * Get the shell from the password data. An empty shell field is 1297af12a3e7SDag-Erling Smørgrav * legal, and means /bin/sh. 1298af12a3e7SDag-Erling Smørgrav */ 1299af12a3e7SDag-Erling Smørgrav shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; 1300af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP 1301af12a3e7SDag-Erling Smørgrav shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell); 1302af12a3e7SDag-Erling Smørgrav #endif 1303af12a3e7SDag-Erling Smørgrav 1304989dd127SDag-Erling Smørgrav env = do_setup_env(s, shell); 1305af12a3e7SDag-Erling Smørgrav 1306af12a3e7SDag-Erling Smørgrav /* we have to stash the hostname before we close our socket. */ 1307af12a3e7SDag-Erling Smørgrav if (options.use_login) 1308af12a3e7SDag-Erling Smørgrav hostname = get_remote_name_or_ip(utmp_len, 1309af12a3e7SDag-Erling Smørgrav options.verify_reverse_mapping); 1310af12a3e7SDag-Erling Smørgrav /* 1311af12a3e7SDag-Erling Smørgrav * Close the connection descriptors; note that this is the child, and 1312af12a3e7SDag-Erling Smørgrav * the server will still have the socket open, and it is important 1313af12a3e7SDag-Erling Smørgrav * that we do not shutdown it. Note that the descriptors cannot be 1314af12a3e7SDag-Erling Smørgrav * closed before building the environment, as we call 1315af12a3e7SDag-Erling Smørgrav * get_remote_ipaddr there. 1316af12a3e7SDag-Erling Smørgrav */ 1317af12a3e7SDag-Erling Smørgrav if (packet_get_connection_in() == packet_get_connection_out()) 1318af12a3e7SDag-Erling Smørgrav close(packet_get_connection_in()); 1319af12a3e7SDag-Erling Smørgrav else { 1320af12a3e7SDag-Erling Smørgrav close(packet_get_connection_in()); 1321af12a3e7SDag-Erling Smørgrav close(packet_get_connection_out()); 1322af12a3e7SDag-Erling Smørgrav } 1323af12a3e7SDag-Erling Smørgrav /* 1324af12a3e7SDag-Erling Smørgrav * Close all descriptors related to channels. They will still remain 1325af12a3e7SDag-Erling Smørgrav * open in the parent. 1326af12a3e7SDag-Erling Smørgrav */ 1327af12a3e7SDag-Erling Smørgrav /* XXX better use close-on-exec? -markus */ 1328af12a3e7SDag-Erling Smørgrav channel_close_all(); 1329af12a3e7SDag-Erling Smørgrav 1330af12a3e7SDag-Erling Smørgrav /* 1331af12a3e7SDag-Erling Smørgrav * Close any extra file descriptors. Note that there may still be 1332af12a3e7SDag-Erling Smørgrav * descriptors left by system functions. They will be closed later. 1333af12a3e7SDag-Erling Smørgrav */ 1334af12a3e7SDag-Erling Smørgrav endpwent(); 1335af12a3e7SDag-Erling Smørgrav 1336af12a3e7SDag-Erling Smørgrav /* 1337af12a3e7SDag-Erling Smørgrav * Close any extra open file descriptors so that we don\'t have them 1338af12a3e7SDag-Erling Smørgrav * hanging around in clients. Note that we want to do this after 1339af12a3e7SDag-Erling Smørgrav * initgroups, because at least on Solaris 2.3 it leaves file 1340af12a3e7SDag-Erling Smørgrav * descriptors open. 1341af12a3e7SDag-Erling Smørgrav */ 1342989dd127SDag-Erling Smørgrav for (i = 3; i < 64; i++) 1343af12a3e7SDag-Erling Smørgrav close(i); 1344af12a3e7SDag-Erling Smørgrav 1345af12a3e7SDag-Erling Smørgrav /* 1346af12a3e7SDag-Erling Smørgrav * Must take new environment into use so that .ssh/rc, 1347af12a3e7SDag-Erling Smørgrav * /etc/ssh/sshrc and xauth are run in the proper environment. 1348af12a3e7SDag-Erling Smørgrav */ 1349af12a3e7SDag-Erling Smørgrav environ = env; 1350af12a3e7SDag-Erling Smørgrav 1351af12a3e7SDag-Erling Smørgrav #ifdef AFS 1352af12a3e7SDag-Erling Smørgrav /* Try to get AFS tokens for the local cell. */ 1353af12a3e7SDag-Erling Smørgrav if (k_hasafs()) { 1354af12a3e7SDag-Erling Smørgrav char cell[64]; 1355af12a3e7SDag-Erling Smørgrav 1356af12a3e7SDag-Erling Smørgrav if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0) 1357af12a3e7SDag-Erling Smørgrav krb_afslog(cell, 0); 1358af12a3e7SDag-Erling Smørgrav 1359af12a3e7SDag-Erling Smørgrav krb_afslog(0, 0); 1360af12a3e7SDag-Erling Smørgrav } 1361af12a3e7SDag-Erling Smørgrav #endif /* AFS */ 1362af12a3e7SDag-Erling Smørgrav 1363af12a3e7SDag-Erling Smørgrav /* Change current directory to the user\'s home directory. */ 1364af12a3e7SDag-Erling Smørgrav if (chdir(pw->pw_dir) < 0) { 1365af12a3e7SDag-Erling Smørgrav fprintf(stderr, "Could not chdir to home directory %s: %s\n", 1366af12a3e7SDag-Erling Smørgrav pw->pw_dir, strerror(errno)); 1367af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP 1368989dd127SDag-Erling Smørgrav if (login_getcapbool(lc, "requirehome", 0)) 1369af12a3e7SDag-Erling Smørgrav exit(1); 1370af12a3e7SDag-Erling Smørgrav #endif 1371af12a3e7SDag-Erling Smørgrav } 1372af12a3e7SDag-Erling Smørgrav 1373af12a3e7SDag-Erling Smørgrav if (!options.use_login) 1374af12a3e7SDag-Erling Smørgrav do_rc_files(s, shell); 1375af12a3e7SDag-Erling Smørgrav 1376ca3176e7SBrian Feldman /* restore SIGPIPE for child */ 1377ca3176e7SBrian Feldman signal(SIGPIPE, SIG_DFL); 1378ca3176e7SBrian Feldman 1379af12a3e7SDag-Erling Smørgrav if (options.use_login) { 138080628bacSDag-Erling Smørgrav launch_login(pw, hostname); 138180628bacSDag-Erling Smørgrav /* NEVERREACHED */ 1382af12a3e7SDag-Erling Smørgrav } 1383af12a3e7SDag-Erling Smørgrav 1384af12a3e7SDag-Erling Smørgrav /* Get the last component of the shell name. */ 1385af12a3e7SDag-Erling Smørgrav if ((shell0 = strrchr(shell, '/')) != NULL) 1386af12a3e7SDag-Erling Smørgrav shell0++; 1387af12a3e7SDag-Erling Smørgrav else 1388af12a3e7SDag-Erling Smørgrav shell0 = shell; 1389af12a3e7SDag-Erling Smørgrav 1390a04a10f8SKris Kennaway /* 1391a04a10f8SKris Kennaway * If we have no command, execute the shell. In this case, the shell 1392a04a10f8SKris Kennaway * name to be passed in argv[0] is preceded by '-' to indicate that 1393a04a10f8SKris Kennaway * this is a login shell. 1394a04a10f8SKris Kennaway */ 1395a04a10f8SKris Kennaway if (!command) { 1396af12a3e7SDag-Erling Smørgrav char argv0[256]; 1397a04a10f8SKris Kennaway 1398a04a10f8SKris Kennaway /* Start the shell. Set initial character to '-'. */ 1399af12a3e7SDag-Erling Smørgrav argv0[0] = '-'; 1400af12a3e7SDag-Erling Smørgrav 1401af12a3e7SDag-Erling Smørgrav if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1) 1402af12a3e7SDag-Erling Smørgrav >= sizeof(argv0) - 1) { 1403af12a3e7SDag-Erling Smørgrav errno = EINVAL; 1404af12a3e7SDag-Erling Smørgrav perror(shell); 1405af12a3e7SDag-Erling Smørgrav exit(1); 1406af12a3e7SDag-Erling Smørgrav } 1407a04a10f8SKris Kennaway 1408a04a10f8SKris Kennaway /* Execute the shell. */ 1409af12a3e7SDag-Erling Smørgrav argv[0] = argv0; 1410a04a10f8SKris Kennaway argv[1] = NULL; 1411a04a10f8SKris Kennaway execve(shell, argv, env); 1412a04a10f8SKris Kennaway 1413a04a10f8SKris Kennaway /* Executing the shell failed. */ 1414a04a10f8SKris Kennaway perror(shell); 1415a04a10f8SKris Kennaway exit(1); 1416a04a10f8SKris Kennaway } 1417a04a10f8SKris Kennaway /* 1418a04a10f8SKris Kennaway * Execute the command using the user's shell. This uses the -c 1419a04a10f8SKris Kennaway * option to execute the command. 1420a04a10f8SKris Kennaway */ 1421af12a3e7SDag-Erling Smørgrav argv[0] = (char *) shell0; 1422a04a10f8SKris Kennaway argv[1] = "-c"; 1423a04a10f8SKris Kennaway argv[2] = (char *) command; 1424a04a10f8SKris Kennaway argv[3] = NULL; 1425a04a10f8SKris Kennaway execve(shell, argv, env); 1426a04a10f8SKris Kennaway perror(shell); 1427a04a10f8SKris Kennaway exit(1); 1428a04a10f8SKris Kennaway } 1429a04a10f8SKris Kennaway 1430a04a10f8SKris Kennaway Session * 1431a04a10f8SKris Kennaway session_new(void) 1432a04a10f8SKris Kennaway { 1433a04a10f8SKris Kennaway int i; 1434a04a10f8SKris Kennaway static int did_init = 0; 1435a04a10f8SKris Kennaway if (!did_init) { 1436a04a10f8SKris Kennaway debug("session_new: init"); 1437a04a10f8SKris Kennaway for (i = 0; i < MAX_SESSIONS; i++) { 1438a04a10f8SKris Kennaway sessions[i].used = 0; 1439a04a10f8SKris Kennaway } 1440a04a10f8SKris Kennaway did_init = 1; 1441a04a10f8SKris Kennaway } 1442a04a10f8SKris Kennaway for (i = 0; i < MAX_SESSIONS; i++) { 1443a04a10f8SKris Kennaway Session *s = &sessions[i]; 1444a04a10f8SKris Kennaway if (! s->used) { 1445ca3176e7SBrian Feldman memset(s, 0, sizeof(*s)); 1446a04a10f8SKris Kennaway s->chanid = -1; 1447a04a10f8SKris Kennaway s->ptyfd = -1; 1448a04a10f8SKris Kennaway s->ttyfd = -1; 1449a04a10f8SKris Kennaway s->used = 1; 1450af12a3e7SDag-Erling Smørgrav s->self = i; 1451a04a10f8SKris Kennaway debug("session_new: session %d", i); 1452a04a10f8SKris Kennaway return s; 1453a04a10f8SKris Kennaway } 1454a04a10f8SKris Kennaway } 1455a04a10f8SKris Kennaway return NULL; 1456a04a10f8SKris Kennaway } 1457a04a10f8SKris Kennaway 1458af12a3e7SDag-Erling Smørgrav static void 1459a04a10f8SKris Kennaway session_dump(void) 1460a04a10f8SKris Kennaway { 1461a04a10f8SKris Kennaway int i; 1462a04a10f8SKris Kennaway for (i = 0; i < MAX_SESSIONS; i++) { 1463a04a10f8SKris Kennaway Session *s = &sessions[i]; 146480628bacSDag-Erling Smørgrav debug("dump: used %d session %d %p channel %d pid %ld", 1465a04a10f8SKris Kennaway s->used, 1466a04a10f8SKris Kennaway s->self, 1467a04a10f8SKris Kennaway s, 1468a04a10f8SKris Kennaway s->chanid, 146980628bacSDag-Erling Smørgrav (long)s->pid); 1470a04a10f8SKris Kennaway } 1471a04a10f8SKris Kennaway } 1472a04a10f8SKris Kennaway 1473a04a10f8SKris Kennaway int 1474af12a3e7SDag-Erling Smørgrav session_open(Authctxt *authctxt, int chanid) 1475a04a10f8SKris Kennaway { 1476a04a10f8SKris Kennaway Session *s = session_new(); 1477a04a10f8SKris Kennaway debug("session_open: channel %d", chanid); 1478a04a10f8SKris Kennaway if (s == NULL) { 1479a04a10f8SKris Kennaway error("no more sessions"); 1480a04a10f8SKris Kennaway return 0; 1481a04a10f8SKris Kennaway } 1482af12a3e7SDag-Erling Smørgrav s->authctxt = authctxt; 1483af12a3e7SDag-Erling Smørgrav s->pw = authctxt->pw; 1484a04a10f8SKris Kennaway if (s->pw == NULL) 1485ca3176e7SBrian Feldman fatal("no user for session %d", s->self); 1486a04a10f8SKris Kennaway debug("session_open: session %d: link with channel %d", s->self, chanid); 1487a04a10f8SKris Kennaway s->chanid = chanid; 1488a04a10f8SKris Kennaway return 1; 1489a04a10f8SKris Kennaway } 1490a04a10f8SKris Kennaway 149180628bacSDag-Erling Smørgrav Session * 149280628bacSDag-Erling Smørgrav session_by_tty(char *tty) 149380628bacSDag-Erling Smørgrav { 149480628bacSDag-Erling Smørgrav int i; 149580628bacSDag-Erling Smørgrav for (i = 0; i < MAX_SESSIONS; i++) { 149680628bacSDag-Erling Smørgrav Session *s = &sessions[i]; 149780628bacSDag-Erling Smørgrav if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) { 149880628bacSDag-Erling Smørgrav debug("session_by_tty: session %d tty %s", i, tty); 149980628bacSDag-Erling Smørgrav return s; 150080628bacSDag-Erling Smørgrav } 150180628bacSDag-Erling Smørgrav } 150280628bacSDag-Erling Smørgrav debug("session_by_tty: unknown tty %.100s", tty); 150380628bacSDag-Erling Smørgrav session_dump(); 150480628bacSDag-Erling Smørgrav return NULL; 150580628bacSDag-Erling Smørgrav } 150680628bacSDag-Erling Smørgrav 1507af12a3e7SDag-Erling Smørgrav static Session * 1508a04a10f8SKris Kennaway session_by_channel(int id) 1509a04a10f8SKris Kennaway { 1510a04a10f8SKris Kennaway int i; 1511a04a10f8SKris Kennaway for (i = 0; i < MAX_SESSIONS; i++) { 1512a04a10f8SKris Kennaway Session *s = &sessions[i]; 1513a04a10f8SKris Kennaway if (s->used && s->chanid == id) { 1514a04a10f8SKris Kennaway debug("session_by_channel: session %d channel %d", i, id); 1515a04a10f8SKris Kennaway return s; 1516a04a10f8SKris Kennaway } 1517a04a10f8SKris Kennaway } 1518a04a10f8SKris Kennaway debug("session_by_channel: unknown channel %d", id); 1519a04a10f8SKris Kennaway session_dump(); 1520a04a10f8SKris Kennaway return NULL; 1521a04a10f8SKris Kennaway } 1522a04a10f8SKris Kennaway 1523af12a3e7SDag-Erling Smørgrav static Session * 1524a04a10f8SKris Kennaway session_by_pid(pid_t pid) 1525a04a10f8SKris Kennaway { 1526a04a10f8SKris Kennaway int i; 152780628bacSDag-Erling Smørgrav debug("session_by_pid: pid %ld", (long)pid); 1528a04a10f8SKris Kennaway for (i = 0; i < MAX_SESSIONS; i++) { 1529a04a10f8SKris Kennaway Session *s = &sessions[i]; 1530a04a10f8SKris Kennaway if (s->used && s->pid == pid) 1531a04a10f8SKris Kennaway return s; 1532a04a10f8SKris Kennaway } 153380628bacSDag-Erling Smørgrav error("session_by_pid: unknown pid %ld", (long)pid); 1534a04a10f8SKris Kennaway session_dump(); 1535a04a10f8SKris Kennaway return NULL; 1536a04a10f8SKris Kennaway } 1537a04a10f8SKris Kennaway 1538af12a3e7SDag-Erling Smørgrav static int 1539a04a10f8SKris Kennaway session_window_change_req(Session *s) 1540a04a10f8SKris Kennaway { 1541a04a10f8SKris Kennaway s->col = packet_get_int(); 1542a04a10f8SKris Kennaway s->row = packet_get_int(); 1543a04a10f8SKris Kennaway s->xpixel = packet_get_int(); 1544a04a10f8SKris Kennaway s->ypixel = packet_get_int(); 1545af12a3e7SDag-Erling Smørgrav packet_check_eom(); 1546a04a10f8SKris Kennaway pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); 1547a04a10f8SKris Kennaway return 1; 1548a04a10f8SKris Kennaway } 1549a04a10f8SKris Kennaway 1550af12a3e7SDag-Erling Smørgrav static int 1551a04a10f8SKris Kennaway session_pty_req(Session *s) 1552a04a10f8SKris Kennaway { 1553ca3176e7SBrian Feldman u_int len; 1554ca3176e7SBrian Feldman int n_bytes; 1555a04a10f8SKris Kennaway 1556af12a3e7SDag-Erling Smørgrav if (no_pty_flag) { 1557af12a3e7SDag-Erling Smørgrav debug("Allocating a pty not permitted for this authentication."); 1558c2d3a559SKris Kennaway return 0; 1559af12a3e7SDag-Erling Smørgrav } 1560af12a3e7SDag-Erling Smørgrav if (s->ttyfd != -1) { 1561af12a3e7SDag-Erling Smørgrav packet_disconnect("Protocol error: you already have a pty."); 1562a04a10f8SKris Kennaway return 0; 1563af12a3e7SDag-Erling Smørgrav } 156480628bacSDag-Erling Smørgrav /* Get the time and hostname when the user last logged in. */ 156580628bacSDag-Erling Smørgrav if (options.print_lastlog) { 156680628bacSDag-Erling Smørgrav s->hostname[0] = '\0'; 156780628bacSDag-Erling Smørgrav s->last_login_time = get_last_login_time(s->pw->pw_uid, 156880628bacSDag-Erling Smørgrav s->pw->pw_name, s->hostname, sizeof(s->hostname)); 156980628bacSDag-Erling Smørgrav } 1570af12a3e7SDag-Erling Smørgrav 1571a04a10f8SKris Kennaway s->term = packet_get_string(&len); 1572af12a3e7SDag-Erling Smørgrav 1573af12a3e7SDag-Erling Smørgrav if (compat20) { 1574a04a10f8SKris Kennaway s->col = packet_get_int(); 1575a04a10f8SKris Kennaway s->row = packet_get_int(); 1576af12a3e7SDag-Erling Smørgrav } else { 1577af12a3e7SDag-Erling Smørgrav s->row = packet_get_int(); 1578af12a3e7SDag-Erling Smørgrav s->col = packet_get_int(); 1579af12a3e7SDag-Erling Smørgrav } 1580a04a10f8SKris Kennaway s->xpixel = packet_get_int(); 1581a04a10f8SKris Kennaway s->ypixel = packet_get_int(); 1582a04a10f8SKris Kennaway 1583a04a10f8SKris Kennaway if (strcmp(s->term, "") == 0) { 1584a04a10f8SKris Kennaway xfree(s->term); 1585a04a10f8SKris Kennaway s->term = NULL; 1586a04a10f8SKris Kennaway } 1587af12a3e7SDag-Erling Smørgrav 1588a04a10f8SKris Kennaway /* Allocate a pty and open it. */ 1589af12a3e7SDag-Erling Smørgrav debug("Allocating pty."); 159080628bacSDag-Erling Smørgrav if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)))) { 1591af12a3e7SDag-Erling Smørgrav if (s->term) 1592a04a10f8SKris Kennaway xfree(s->term); 1593a04a10f8SKris Kennaway s->term = NULL; 1594a04a10f8SKris Kennaway s->ptyfd = -1; 1595a04a10f8SKris Kennaway s->ttyfd = -1; 1596a04a10f8SKris Kennaway error("session_pty_req: session %d alloc failed", s->self); 1597a04a10f8SKris Kennaway return 0; 1598a04a10f8SKris Kennaway } 1599a04a10f8SKris Kennaway debug("session_pty_req: session %d alloc %s", s->self, s->tty); 1600af12a3e7SDag-Erling Smørgrav 1601af12a3e7SDag-Erling Smørgrav /* for SSH1 the tty modes length is not given */ 1602af12a3e7SDag-Erling Smørgrav if (!compat20) 1603af12a3e7SDag-Erling Smørgrav n_bytes = packet_remaining(); 1604af12a3e7SDag-Erling Smørgrav tty_parse_modes(s->ttyfd, &n_bytes); 1605af12a3e7SDag-Erling Smørgrav 1606a04a10f8SKris Kennaway /* 1607a04a10f8SKris Kennaway * Add a cleanup function to clear the utmp entry and record logout 1608a04a10f8SKris Kennaway * time in case we call fatal() (e.g., the connection gets closed). 1609a04a10f8SKris Kennaway */ 1610af12a3e7SDag-Erling Smørgrav fatal_add_cleanup(session_pty_cleanup, (void *)s); 161180628bacSDag-Erling Smørgrav if (!use_privsep) 1612a04a10f8SKris Kennaway pty_setowner(s->pw, s->tty); 1613af12a3e7SDag-Erling Smørgrav 1614af12a3e7SDag-Erling Smørgrav /* Set window size from the packet. */ 1615a04a10f8SKris Kennaway pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); 1616a04a10f8SKris Kennaway 1617af12a3e7SDag-Erling Smørgrav packet_check_eom(); 1618a04a10f8SKris Kennaway session_proctitle(s); 1619a04a10f8SKris Kennaway return 1; 1620a04a10f8SKris Kennaway } 1621a04a10f8SKris Kennaway 1622af12a3e7SDag-Erling Smørgrav static int 1623a04a10f8SKris Kennaway session_subsystem_req(Session *s) 1624a04a10f8SKris Kennaway { 1625af12a3e7SDag-Erling Smørgrav struct stat st; 1626ca3176e7SBrian Feldman u_int len; 1627a04a10f8SKris Kennaway int success = 0; 1628af12a3e7SDag-Erling Smørgrav char *cmd, *subsys = packet_get_string(&len); 1629c2d3a559SKris Kennaway int i; 1630a04a10f8SKris Kennaway 1631af12a3e7SDag-Erling Smørgrav packet_check_eom(); 1632af12a3e7SDag-Erling Smørgrav log("subsystem request for %.100s", subsys); 1633a04a10f8SKris Kennaway 1634c2d3a559SKris Kennaway for (i = 0; i < options.num_subsystems; i++) { 1635c2d3a559SKris Kennaway if (strcmp(subsys, options.subsystem_name[i]) == 0) { 1636af12a3e7SDag-Erling Smørgrav cmd = options.subsystem_command[i]; 1637af12a3e7SDag-Erling Smørgrav if (stat(cmd, &st) < 0) { 1638af12a3e7SDag-Erling Smørgrav error("subsystem: cannot stat %s: %s", cmd, 1639af12a3e7SDag-Erling Smørgrav strerror(errno)); 1640af12a3e7SDag-Erling Smørgrav break; 1641af12a3e7SDag-Erling Smørgrav } 1642af12a3e7SDag-Erling Smørgrav debug("subsystem: exec() %s", cmd); 1643ca3176e7SBrian Feldman s->is_subsystem = 1; 1644af12a3e7SDag-Erling Smørgrav do_exec(s, cmd); 1645c2d3a559SKris Kennaway success = 1; 1646af12a3e7SDag-Erling Smørgrav break; 1647c2d3a559SKris Kennaway } 1648c2d3a559SKris Kennaway } 1649c2d3a559SKris Kennaway 1650c2d3a559SKris Kennaway if (!success) 1651af12a3e7SDag-Erling Smørgrav log("subsystem request for %.100s failed, subsystem not found", 1652af12a3e7SDag-Erling Smørgrav subsys); 1653c2d3a559SKris Kennaway 1654a04a10f8SKris Kennaway xfree(subsys); 1655a04a10f8SKris Kennaway return success; 1656a04a10f8SKris Kennaway } 1657a04a10f8SKris Kennaway 1658af12a3e7SDag-Erling Smørgrav static int 1659a04a10f8SKris Kennaway session_x11_req(Session *s) 1660a04a10f8SKris Kennaway { 1661af12a3e7SDag-Erling Smørgrav int success; 1662a04a10f8SKris Kennaway 1663a04a10f8SKris Kennaway s->single_connection = packet_get_char(); 1664a04a10f8SKris Kennaway s->auth_proto = packet_get_string(NULL); 1665a04a10f8SKris Kennaway s->auth_data = packet_get_string(NULL); 1666a04a10f8SKris Kennaway s->screen = packet_get_int(); 1667af12a3e7SDag-Erling Smørgrav packet_check_eom(); 1668a04a10f8SKris Kennaway 1669af12a3e7SDag-Erling Smørgrav success = session_setup_x11fwd(s); 1670af12a3e7SDag-Erling Smørgrav if (!success) { 1671a04a10f8SKris Kennaway xfree(s->auth_proto); 1672a04a10f8SKris Kennaway xfree(s->auth_data); 1673af12a3e7SDag-Erling Smørgrav s->auth_proto = NULL; 1674af12a3e7SDag-Erling Smørgrav s->auth_data = NULL; 1675a04a10f8SKris Kennaway } 1676af12a3e7SDag-Erling Smørgrav return success; 1677a04a10f8SKris Kennaway } 1678a04a10f8SKris Kennaway 1679af12a3e7SDag-Erling Smørgrav static int 1680c2d3a559SKris Kennaway session_shell_req(Session *s) 1681c2d3a559SKris Kennaway { 1682af12a3e7SDag-Erling Smørgrav packet_check_eom(); 1683af12a3e7SDag-Erling Smørgrav do_exec(s, NULL); 1684c2d3a559SKris Kennaway return 1; 1685c2d3a559SKris Kennaway } 1686c2d3a559SKris Kennaway 1687af12a3e7SDag-Erling Smørgrav static int 1688c2d3a559SKris Kennaway session_exec_req(Session *s) 1689c2d3a559SKris Kennaway { 1690ca3176e7SBrian Feldman u_int len; 1691c2d3a559SKris Kennaway char *command = packet_get_string(&len); 1692af12a3e7SDag-Erling Smørgrav packet_check_eom(); 1693af12a3e7SDag-Erling Smørgrav do_exec(s, command); 1694c2d3a559SKris Kennaway xfree(command); 1695c2d3a559SKris Kennaway return 1; 1696c2d3a559SKris Kennaway } 1697c2d3a559SKris Kennaway 1698af12a3e7SDag-Erling Smørgrav static int 1699ca3176e7SBrian Feldman session_auth_agent_req(Session *s) 1700ca3176e7SBrian Feldman { 1701ca3176e7SBrian Feldman static int called = 0; 1702af12a3e7SDag-Erling Smørgrav packet_check_eom(); 1703ca3176e7SBrian Feldman if (no_agent_forwarding_flag) { 1704ca3176e7SBrian Feldman debug("session_auth_agent_req: no_agent_forwarding_flag"); 1705ca3176e7SBrian Feldman return 0; 1706ca3176e7SBrian Feldman } 1707ca3176e7SBrian Feldman if (called) { 1708ca3176e7SBrian Feldman return 0; 1709ca3176e7SBrian Feldman } else { 1710ca3176e7SBrian Feldman called = 1; 1711ca3176e7SBrian Feldman return auth_input_request_forwarding(s->pw); 1712ca3176e7SBrian Feldman } 1713ca3176e7SBrian Feldman } 1714ca3176e7SBrian Feldman 1715af12a3e7SDag-Erling Smørgrav int 1716af12a3e7SDag-Erling Smørgrav session_input_channel_req(Channel *c, const char *rtype) 1717a04a10f8SKris Kennaway { 1718a04a10f8SKris Kennaway int success = 0; 1719a04a10f8SKris Kennaway Session *s; 1720a04a10f8SKris Kennaway 1721af12a3e7SDag-Erling Smørgrav if ((s = session_by_channel(c->self)) == NULL) { 1722af12a3e7SDag-Erling Smørgrav log("session_input_channel_req: no session %d req %.100s", 1723af12a3e7SDag-Erling Smørgrav c->self, rtype); 1724af12a3e7SDag-Erling Smørgrav return 0; 1725af12a3e7SDag-Erling Smørgrav } 1726af12a3e7SDag-Erling Smørgrav debug("session_input_channel_req: session %d req %s", s->self, rtype); 1727a04a10f8SKris Kennaway 1728a04a10f8SKris Kennaway /* 1729ca3176e7SBrian Feldman * a session is in LARVAL state until a shell, a command 1730ca3176e7SBrian Feldman * or a subsystem is executed 1731a04a10f8SKris Kennaway */ 1732a04a10f8SKris Kennaway if (c->type == SSH_CHANNEL_LARVAL) { 1733a04a10f8SKris Kennaway if (strcmp(rtype, "shell") == 0) { 1734c2d3a559SKris Kennaway success = session_shell_req(s); 1735a04a10f8SKris Kennaway } else if (strcmp(rtype, "exec") == 0) { 1736c2d3a559SKris Kennaway success = session_exec_req(s); 1737a04a10f8SKris Kennaway } else if (strcmp(rtype, "pty-req") == 0) { 1738a04a10f8SKris Kennaway success = session_pty_req(s); 1739a04a10f8SKris Kennaway } else if (strcmp(rtype, "x11-req") == 0) { 1740a04a10f8SKris Kennaway success = session_x11_req(s); 1741ca3176e7SBrian Feldman } else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) { 1742ca3176e7SBrian Feldman success = session_auth_agent_req(s); 1743a04a10f8SKris Kennaway } else if (strcmp(rtype, "subsystem") == 0) { 1744a04a10f8SKris Kennaway success = session_subsystem_req(s); 1745a04a10f8SKris Kennaway } 1746a04a10f8SKris Kennaway } 1747a04a10f8SKris Kennaway if (strcmp(rtype, "window-change") == 0) { 1748a04a10f8SKris Kennaway success = session_window_change_req(s); 1749a04a10f8SKris Kennaway } 1750af12a3e7SDag-Erling Smørgrav return success; 1751a04a10f8SKris Kennaway } 1752a04a10f8SKris Kennaway 1753a04a10f8SKris Kennaway void 1754a04a10f8SKris Kennaway session_set_fds(Session *s, int fdin, int fdout, int fderr) 1755a04a10f8SKris Kennaway { 1756a04a10f8SKris Kennaway if (!compat20) 1757a04a10f8SKris Kennaway fatal("session_set_fds: called for proto != 2.0"); 1758a04a10f8SKris Kennaway /* 1759a04a10f8SKris Kennaway * now that have a child and a pipe to the child, 1760a04a10f8SKris Kennaway * we can activate our channel and register the fd's 1761a04a10f8SKris Kennaway */ 1762a04a10f8SKris Kennaway if (s->chanid == -1) 1763a04a10f8SKris Kennaway fatal("no channel for session %d", s->self); 1764a04a10f8SKris Kennaway channel_set_fds(s->chanid, 1765a04a10f8SKris Kennaway fdout, fdin, fderr, 176609958426SBrian Feldman fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, 1767af12a3e7SDag-Erling Smørgrav 1, 1768af12a3e7SDag-Erling Smørgrav CHAN_SES_WINDOW_DEFAULT); 1769a04a10f8SKris Kennaway } 1770a04a10f8SKris Kennaway 1771af12a3e7SDag-Erling Smørgrav /* 1772af12a3e7SDag-Erling Smørgrav * Function to perform pty cleanup. Also called if we get aborted abnormally 1773af12a3e7SDag-Erling Smørgrav * (e.g., due to a dropped connection). 1774af12a3e7SDag-Erling Smørgrav */ 177580628bacSDag-Erling Smørgrav void 177680628bacSDag-Erling Smørgrav session_pty_cleanup2(void *session) 1777a04a10f8SKris Kennaway { 1778af12a3e7SDag-Erling Smørgrav Session *s = session; 1779af12a3e7SDag-Erling Smørgrav 1780af12a3e7SDag-Erling Smørgrav if (s == NULL) { 1781af12a3e7SDag-Erling Smørgrav error("session_pty_cleanup: no session"); 1782af12a3e7SDag-Erling Smørgrav return; 1783af12a3e7SDag-Erling Smørgrav } 1784af12a3e7SDag-Erling Smørgrav if (s->ttyfd == -1) 1785a04a10f8SKris Kennaway return; 1786a04a10f8SKris Kennaway 1787ca3176e7SBrian Feldman debug("session_pty_cleanup: session %d release %s", s->self, s->tty); 1788a04a10f8SKris Kennaway 1789a04a10f8SKris Kennaway /* Record that the user has logged out. */ 1790af12a3e7SDag-Erling Smørgrav if (s->pid != 0) 1791989dd127SDag-Erling Smørgrav record_logout(s->pid, s->tty, s->pw->pw_name); 1792a04a10f8SKris Kennaway 1793a04a10f8SKris Kennaway /* Release the pseudo-tty. */ 179480628bacSDag-Erling Smørgrav if (getuid() == 0) 1795a04a10f8SKris Kennaway pty_release(s->tty); 1796a04a10f8SKris Kennaway 1797a04a10f8SKris Kennaway /* 1798a04a10f8SKris Kennaway * Close the server side of the socket pairs. We must do this after 1799a04a10f8SKris Kennaway * the pty cleanup, so that another process doesn't get this pty 1800a04a10f8SKris Kennaway * while we're still cleaning up. 1801a04a10f8SKris Kennaway */ 1802a04a10f8SKris Kennaway if (close(s->ptymaster) < 0) 180380628bacSDag-Erling Smørgrav error("close(s->ptymaster/%d): %s", s->ptymaster, strerror(errno)); 1804af12a3e7SDag-Erling Smørgrav 1805af12a3e7SDag-Erling Smørgrav /* unlink pty from session */ 1806af12a3e7SDag-Erling Smørgrav s->ttyfd = -1; 1807a04a10f8SKris Kennaway } 1808a04a10f8SKris Kennaway 180980628bacSDag-Erling Smørgrav void 181080628bacSDag-Erling Smørgrav session_pty_cleanup(void *session) 181180628bacSDag-Erling Smørgrav { 181280628bacSDag-Erling Smørgrav PRIVSEP(session_pty_cleanup2(session)); 181380628bacSDag-Erling Smørgrav } 181480628bacSDag-Erling Smørgrav 1815af12a3e7SDag-Erling Smørgrav static void 1816a04a10f8SKris Kennaway session_exit_message(Session *s, int status) 1817a04a10f8SKris Kennaway { 1818a04a10f8SKris Kennaway Channel *c; 1819af12a3e7SDag-Erling Smørgrav 1820af12a3e7SDag-Erling Smørgrav if ((c = channel_lookup(s->chanid)) == NULL) 1821af12a3e7SDag-Erling Smørgrav fatal("session_exit_message: session %d: no channel %d", 1822a04a10f8SKris Kennaway s->self, s->chanid); 182380628bacSDag-Erling Smørgrav debug("session_exit_message: session %d channel %d pid %ld", 182480628bacSDag-Erling Smørgrav s->self, s->chanid, (long)s->pid); 1825a04a10f8SKris Kennaway 1826a04a10f8SKris Kennaway if (WIFEXITED(status)) { 1827af12a3e7SDag-Erling Smørgrav channel_request_start(s->chanid, "exit-status", 0); 1828a04a10f8SKris Kennaway packet_put_int(WEXITSTATUS(status)); 1829a04a10f8SKris Kennaway packet_send(); 1830a04a10f8SKris Kennaway } else if (WIFSIGNALED(status)) { 1831af12a3e7SDag-Erling Smørgrav channel_request_start(s->chanid, "exit-signal", 0); 1832a04a10f8SKris Kennaway packet_put_int(WTERMSIG(status)); 1833989dd127SDag-Erling Smørgrav #ifdef WCOREDUMP 1834a04a10f8SKris Kennaway packet_put_char(WCOREDUMP(status)); 1835989dd127SDag-Erling Smørgrav #else /* WCOREDUMP */ 1836989dd127SDag-Erling Smørgrav packet_put_char(0); 1837989dd127SDag-Erling Smørgrav #endif /* WCOREDUMP */ 1838a04a10f8SKris Kennaway packet_put_cstring(""); 1839a04a10f8SKris Kennaway packet_put_cstring(""); 1840a04a10f8SKris Kennaway packet_send(); 1841a04a10f8SKris Kennaway } else { 1842a04a10f8SKris Kennaway /* Some weird exit cause. Just exit. */ 1843a04a10f8SKris Kennaway packet_disconnect("wait returned status %04x.", status); 1844a04a10f8SKris Kennaway } 1845a04a10f8SKris Kennaway 1846a04a10f8SKris Kennaway /* disconnect channel */ 1847a04a10f8SKris Kennaway debug("session_exit_message: release channel %d", s->chanid); 1848a04a10f8SKris Kennaway channel_cancel_cleanup(s->chanid); 1849a04a10f8SKris Kennaway /* 1850a04a10f8SKris Kennaway * emulate a write failure with 'chan_write_failed', nobody will be 1851a04a10f8SKris Kennaway * interested in data we write. 1852a04a10f8SKris Kennaway * Note that we must not call 'chan_read_failed', since there could 1853a04a10f8SKris Kennaway * be some more data waiting in the pipe. 1854a04a10f8SKris Kennaway */ 1855a04a10f8SKris Kennaway if (c->ostate != CHAN_OUTPUT_CLOSED) 1856a04a10f8SKris Kennaway chan_write_failed(c); 1857a04a10f8SKris Kennaway s->chanid = -1; 1858a04a10f8SKris Kennaway } 1859a04a10f8SKris Kennaway 186080628bacSDag-Erling Smørgrav void 1861af12a3e7SDag-Erling Smørgrav session_close(Session *s) 1862a04a10f8SKris Kennaway { 186380628bacSDag-Erling Smørgrav debug("session_close: session %d pid %ld", s->self, (long)s->pid); 1864af12a3e7SDag-Erling Smørgrav if (s->ttyfd != -1) { 1865af12a3e7SDag-Erling Smørgrav fatal_remove_cleanup(session_pty_cleanup, (void *)s); 1866af12a3e7SDag-Erling Smørgrav session_pty_cleanup(s); 1867af12a3e7SDag-Erling Smørgrav } 1868a04a10f8SKris Kennaway if (s->term) 1869a04a10f8SKris Kennaway xfree(s->term); 1870a04a10f8SKris Kennaway if (s->display) 1871a04a10f8SKris Kennaway xfree(s->display); 1872af12a3e7SDag-Erling Smørgrav if (s->auth_display) 1873af12a3e7SDag-Erling Smørgrav xfree(s->auth_display); 1874a04a10f8SKris Kennaway if (s->auth_data) 1875a04a10f8SKris Kennaway xfree(s->auth_data); 1876a04a10f8SKris Kennaway if (s->auth_proto) 1877a04a10f8SKris Kennaway xfree(s->auth_proto); 1878a04a10f8SKris Kennaway s->used = 0; 1879a04a10f8SKris Kennaway session_proctitle(s); 1880a04a10f8SKris Kennaway } 1881a04a10f8SKris Kennaway 1882a04a10f8SKris Kennaway void 1883a04a10f8SKris Kennaway session_close_by_pid(pid_t pid, int status) 1884a04a10f8SKris Kennaway { 1885a04a10f8SKris Kennaway Session *s = session_by_pid(pid); 1886a04a10f8SKris Kennaway if (s == NULL) { 188780628bacSDag-Erling Smørgrav debug("session_close_by_pid: no session for pid %ld", 188880628bacSDag-Erling Smørgrav (long)pid); 1889a04a10f8SKris Kennaway return; 1890a04a10f8SKris Kennaway } 1891a04a10f8SKris Kennaway if (s->chanid != -1) 1892a04a10f8SKris Kennaway session_exit_message(s, status); 1893a04a10f8SKris Kennaway session_close(s); 1894a04a10f8SKris Kennaway } 1895a04a10f8SKris Kennaway 1896a04a10f8SKris Kennaway /* 1897a04a10f8SKris Kennaway * this is called when a channel dies before 1898a04a10f8SKris Kennaway * the session 'child' itself dies 1899a04a10f8SKris Kennaway */ 1900a04a10f8SKris Kennaway void 1901a04a10f8SKris Kennaway session_close_by_channel(int id, void *arg) 1902a04a10f8SKris Kennaway { 1903a04a10f8SKris Kennaway Session *s = session_by_channel(id); 1904a04a10f8SKris Kennaway if (s == NULL) { 1905af12a3e7SDag-Erling Smørgrav debug("session_close_by_channel: no session for id %d", id); 1906a04a10f8SKris Kennaway return; 1907a04a10f8SKris Kennaway } 190880628bacSDag-Erling Smørgrav debug("session_close_by_channel: channel %d child %ld", 190980628bacSDag-Erling Smørgrav id, (long)s->pid); 1910af12a3e7SDag-Erling Smørgrav if (s->pid != 0) { 1911af12a3e7SDag-Erling Smørgrav debug("session_close_by_channel: channel %d: has child", id); 1912af12a3e7SDag-Erling Smørgrav /* 1913af12a3e7SDag-Erling Smørgrav * delay detach of session, but release pty, since 1914af12a3e7SDag-Erling Smørgrav * the fd's to the child are already closed 1915af12a3e7SDag-Erling Smørgrav */ 1916af12a3e7SDag-Erling Smørgrav if (s->ttyfd != -1) { 1917af12a3e7SDag-Erling Smørgrav fatal_remove_cleanup(session_pty_cleanup, (void *)s); 1918af12a3e7SDag-Erling Smørgrav session_pty_cleanup(s); 1919af12a3e7SDag-Erling Smørgrav } 1920af12a3e7SDag-Erling Smørgrav return; 1921af12a3e7SDag-Erling Smørgrav } 1922af12a3e7SDag-Erling Smørgrav /* detach by removing callback */ 1923a04a10f8SKris Kennaway channel_cancel_cleanup(s->chanid); 1924a04a10f8SKris Kennaway s->chanid = -1; 1925a04a10f8SKris Kennaway session_close(s); 1926af12a3e7SDag-Erling Smørgrav } 1927af12a3e7SDag-Erling Smørgrav 1928af12a3e7SDag-Erling Smørgrav void 192980628bacSDag-Erling Smørgrav session_destroy_all(void (*closefunc)(Session *)) 1930af12a3e7SDag-Erling Smørgrav { 1931af12a3e7SDag-Erling Smørgrav int i; 1932af12a3e7SDag-Erling Smørgrav for (i = 0; i < MAX_SESSIONS; i++) { 1933af12a3e7SDag-Erling Smørgrav Session *s = &sessions[i]; 193480628bacSDag-Erling Smørgrav if (s->used) { 193580628bacSDag-Erling Smørgrav if (closefunc != NULL) 193680628bacSDag-Erling Smørgrav closefunc(s); 193780628bacSDag-Erling Smørgrav else 1938af12a3e7SDag-Erling Smørgrav session_close(s); 1939a04a10f8SKris Kennaway } 1940a04a10f8SKris Kennaway } 194180628bacSDag-Erling Smørgrav } 1942a04a10f8SKris Kennaway 1943af12a3e7SDag-Erling Smørgrav static char * 1944a04a10f8SKris Kennaway session_tty_list(void) 1945a04a10f8SKris Kennaway { 1946a04a10f8SKris Kennaway static char buf[1024]; 1947a04a10f8SKris Kennaway int i; 1948a04a10f8SKris Kennaway buf[0] = '\0'; 1949a04a10f8SKris Kennaway for (i = 0; i < MAX_SESSIONS; i++) { 1950a04a10f8SKris Kennaway Session *s = &sessions[i]; 1951a04a10f8SKris Kennaway if (s->used && s->ttyfd != -1) { 1952a04a10f8SKris Kennaway if (buf[0] != '\0') 1953a04a10f8SKris Kennaway strlcat(buf, ",", sizeof buf); 1954a04a10f8SKris Kennaway strlcat(buf, strrchr(s->tty, '/') + 1, sizeof buf); 1955a04a10f8SKris Kennaway } 1956a04a10f8SKris Kennaway } 1957a04a10f8SKris Kennaway if (buf[0] == '\0') 1958a04a10f8SKris Kennaway strlcpy(buf, "notty", sizeof buf); 1959a04a10f8SKris Kennaway return buf; 1960a04a10f8SKris Kennaway } 1961a04a10f8SKris Kennaway 1962a04a10f8SKris Kennaway void 1963a04a10f8SKris Kennaway session_proctitle(Session *s) 1964a04a10f8SKris Kennaway { 1965a04a10f8SKris Kennaway if (s->pw == NULL) 1966a04a10f8SKris Kennaway error("no user for session %d", s->self); 1967a04a10f8SKris Kennaway else 1968a04a10f8SKris Kennaway setproctitle("%s@%s", s->pw->pw_name, session_tty_list()); 1969a04a10f8SKris Kennaway } 1970a04a10f8SKris Kennaway 1971af12a3e7SDag-Erling Smørgrav int 1972af12a3e7SDag-Erling Smørgrav session_setup_x11fwd(Session *s) 1973af12a3e7SDag-Erling Smørgrav { 1974af12a3e7SDag-Erling Smørgrav struct stat st; 1975af12a3e7SDag-Erling Smørgrav char display[512], auth_display[512]; 1976af12a3e7SDag-Erling Smørgrav char hostname[MAXHOSTNAMELEN]; 1977af12a3e7SDag-Erling Smørgrav 1978af12a3e7SDag-Erling Smørgrav if (no_x11_forwarding_flag) { 1979af12a3e7SDag-Erling Smørgrav packet_send_debug("X11 forwarding disabled in user configuration file."); 1980af12a3e7SDag-Erling Smørgrav return 0; 1981af12a3e7SDag-Erling Smørgrav } 1982af12a3e7SDag-Erling Smørgrav if (!options.x11_forwarding) { 1983af12a3e7SDag-Erling Smørgrav debug("X11 forwarding disabled in server configuration file."); 1984af12a3e7SDag-Erling Smørgrav return 0; 1985af12a3e7SDag-Erling Smørgrav } 1986af12a3e7SDag-Erling Smørgrav if (!options.xauth_location || 1987af12a3e7SDag-Erling Smørgrav (stat(options.xauth_location, &st) == -1)) { 1988af12a3e7SDag-Erling Smørgrav packet_send_debug("No xauth program; cannot forward with spoofing."); 1989af12a3e7SDag-Erling Smørgrav return 0; 1990af12a3e7SDag-Erling Smørgrav } 1991af12a3e7SDag-Erling Smørgrav if (options.use_login) { 1992af12a3e7SDag-Erling Smørgrav packet_send_debug("X11 forwarding disabled; " 1993af12a3e7SDag-Erling Smørgrav "not compatible with UseLogin=yes."); 1994af12a3e7SDag-Erling Smørgrav return 0; 1995af12a3e7SDag-Erling Smørgrav } 1996af12a3e7SDag-Erling Smørgrav if (s->display != NULL) { 1997af12a3e7SDag-Erling Smørgrav debug("X11 display already set."); 1998af12a3e7SDag-Erling Smørgrav return 0; 1999af12a3e7SDag-Erling Smørgrav } 2000a82e551fSDag-Erling Smørgrav if (x11_create_display_inet(options.x11_display_offset, 2001a82e551fSDag-Erling Smørgrav options.x11_use_localhost, s->single_connection, 2002a82e551fSDag-Erling Smørgrav &s->display_number) == -1) { 2003af12a3e7SDag-Erling Smørgrav debug("x11_create_display_inet failed."); 2004af12a3e7SDag-Erling Smørgrav return 0; 2005af12a3e7SDag-Erling Smørgrav } 2006af12a3e7SDag-Erling Smørgrav 2007af12a3e7SDag-Erling Smørgrav /* Set up a suitable value for the DISPLAY variable. */ 2008af12a3e7SDag-Erling Smørgrav if (gethostname(hostname, sizeof(hostname)) < 0) 2009af12a3e7SDag-Erling Smørgrav fatal("gethostname: %.100s", strerror(errno)); 2010af12a3e7SDag-Erling Smørgrav /* 2011af12a3e7SDag-Erling Smørgrav * auth_display must be used as the displayname when the 2012af12a3e7SDag-Erling Smørgrav * authorization entry is added with xauth(1). This will be 2013af12a3e7SDag-Erling Smørgrav * different than the DISPLAY string for localhost displays. 2014af12a3e7SDag-Erling Smørgrav */ 2015af12a3e7SDag-Erling Smørgrav if (options.x11_use_localhost) { 2016a82e551fSDag-Erling Smørgrav snprintf(display, sizeof display, "localhost:%u.%u", 2017af12a3e7SDag-Erling Smørgrav s->display_number, s->screen); 2018a82e551fSDag-Erling Smørgrav snprintf(auth_display, sizeof auth_display, "unix:%u.%u", 2019af12a3e7SDag-Erling Smørgrav s->display_number, s->screen); 2020af12a3e7SDag-Erling Smørgrav s->display = xstrdup(display); 2021af12a3e7SDag-Erling Smørgrav s->auth_display = xstrdup(auth_display); 2022af12a3e7SDag-Erling Smørgrav } else { 2023989dd127SDag-Erling Smørgrav #ifdef IPADDR_IN_DISPLAY 2024989dd127SDag-Erling Smørgrav struct hostent *he; 2025989dd127SDag-Erling Smørgrav struct in_addr my_addr; 2026989dd127SDag-Erling Smørgrav 2027989dd127SDag-Erling Smørgrav he = gethostbyname(hostname); 2028989dd127SDag-Erling Smørgrav if (he == NULL) { 2029989dd127SDag-Erling Smørgrav error("Can't get IP address for X11 DISPLAY."); 2030989dd127SDag-Erling Smørgrav packet_send_debug("Can't get IP address for X11 DISPLAY."); 2031989dd127SDag-Erling Smørgrav return 0; 2032989dd127SDag-Erling Smørgrav } 2033989dd127SDag-Erling Smørgrav memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr)); 2034a82e551fSDag-Erling Smørgrav snprintf(display, sizeof display, "%.50s:%u.%u", inet_ntoa(my_addr), 2035989dd127SDag-Erling Smørgrav s->display_number, s->screen); 2036989dd127SDag-Erling Smørgrav #else 2037a82e551fSDag-Erling Smørgrav snprintf(display, sizeof display, "%.400s:%u.%u", hostname, 2038af12a3e7SDag-Erling Smørgrav s->display_number, s->screen); 2039989dd127SDag-Erling Smørgrav #endif 2040af12a3e7SDag-Erling Smørgrav s->display = xstrdup(display); 2041af12a3e7SDag-Erling Smørgrav s->auth_display = xstrdup(display); 2042af12a3e7SDag-Erling Smørgrav } 2043af12a3e7SDag-Erling Smørgrav 2044af12a3e7SDag-Erling Smørgrav return 1; 2045af12a3e7SDag-Erling Smørgrav } 2046af12a3e7SDag-Erling Smørgrav 2047af12a3e7SDag-Erling Smørgrav static void 2048ca3176e7SBrian Feldman do_authenticated2(Authctxt *authctxt) 2049a04a10f8SKris Kennaway { 2050af12a3e7SDag-Erling Smørgrav server_loop2(authctxt); 2051a04a10f8SKris Kennaway } 2052