1323124Sdes/* $OpenBSD: session.c,v 1.282 2016/03/10 11:47:57 djm Exp $ */ 260573Skris/* 360573Skris * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 460573Skris * All rights reserved 565674Skris * 665674Skris * As far as I am concerned, the code I have written for this software 765674Skris * can be used freely for any purpose. Any derived versions of this 865674Skris * software must be clearly marked as such, and if the derived work is 965674Skris * incompatible with the protocol description in the RFC file, it must be 1065674Skris * called by a name other than "ssh" or "Secure Shell". 1165674Skris * 1260573Skris * SSH2 support by Markus Friedl. 1392559Sdes * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 1460576Skris * 1565674Skris * Redistribution and use in source and binary forms, with or without 1665674Skris * modification, are permitted provided that the following conditions 1765674Skris * are met: 1865674Skris * 1. Redistributions of source code must retain the above copyright 1965674Skris * notice, this list of conditions and the following disclaimer. 2065674Skris * 2. Redistributions in binary form must reproduce the above copyright 2165674Skris * notice, this list of conditions and the following disclaimer in the 2265674Skris * documentation and/or other materials provided with the distribution. 2365674Skris * 2465674Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2565674Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2665674Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2765674Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2865674Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2965674Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3065674Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3165674Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3265674Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3365674Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3460573Skris */ 3560573Skris 3660573Skris#include "includes.h" 37162856Sdes__RCSID("$FreeBSD: stable/10/crypto/openssh/session.c 323124 2017-09-01 22:52:18Z des $"); 3860573Skris 39162856Sdes#include <sys/types.h> 40162856Sdes#include <sys/param.h> 41162856Sdes#ifdef HAVE_SYS_STAT_H 42162856Sdes# include <sys/stat.h> 43162856Sdes#endif 44162856Sdes#include <sys/socket.h> 45162856Sdes#include <sys/un.h> 46162856Sdes#include <sys/wait.h> 47162856Sdes 48162856Sdes#include <arpa/inet.h> 49162856Sdes 50296781Sdes#include <ctype.h> 51162856Sdes#include <errno.h> 52215116Sdes#include <fcntl.h> 53162856Sdes#include <grp.h> 54295367Sdes#include <netdb.h> 55162856Sdes#ifdef HAVE_PATHS_H 56162856Sdes#include <paths.h> 57162856Sdes#endif 58162856Sdes#include <pwd.h> 59162856Sdes#include <signal.h> 60162856Sdes#include <stdarg.h> 61162856Sdes#include <stdio.h> 62162856Sdes#include <stdlib.h> 63162856Sdes#include <string.h> 64162856Sdes#include <unistd.h> 65295367Sdes#include <limits.h> 66162856Sdes 67181111Sdes#include "openbsd-compat/sys-queue.h" 68162856Sdes#include "xmalloc.h" 6976262Sgreen#include "ssh.h" 7076262Sgreen#include "ssh1.h" 7176262Sgreen#include "ssh2.h" 7276262Sgreen#include "sshpty.h" 7360573Skris#include "packet.h" 7460573Skris#include "buffer.h" 75137019Sdes#include "match.h" 7660573Skris#include "uidswap.h" 7760573Skris#include "compat.h" 7860573Skris#include "channels.h" 79162856Sdes#include "key.h" 80162856Sdes#include "cipher.h" 81162856Sdes#ifdef GSSAPI 82162856Sdes#include "ssh-gss.h" 83162856Sdes#endif 84162856Sdes#include "hostfile.h" 8560573Skris#include "auth.h" 8665674Skris#include "auth-options.h" 87255767Sdes#include "authfd.h" 8876262Sgreen#include "pathnames.h" 8976262Sgreen#include "log.h" 90295367Sdes#include "misc.h" 9176262Sgreen#include "servconf.h" 9276262Sgreen#include "sshlogin.h" 9376262Sgreen#include "serverloop.h" 9476262Sgreen#include "canohost.h" 9576262Sgreen#include "session.h" 96149753Sdes#include "kex.h" 9798684Sdes#include "monitor_wrap.h" 98181111Sdes#include "sftp.h" 9960573Skris 100126277Sdes#if defined(KRB5) && defined(USE_AFS) 101126277Sdes#include <kafs.h> 102126277Sdes#endif 103126277Sdes 104226046Sdes#ifdef WITH_SELINUX 105226046Sdes#include <selinux/selinux.h> 106226046Sdes#endif 107226046Sdes 108192595Sdes#define IS_INTERNAL_SFTP(c) \ 109192595Sdes (!strncmp(c, INTERNAL_SFTP_NAME, sizeof(INTERNAL_SFTP_NAME) - 1) && \ 110192595Sdes (c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\0' || \ 111192595Sdes c[sizeof(INTERNAL_SFTP_NAME) - 1] == ' ' || \ 112192595Sdes c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\t')) 113192595Sdes 11460573Skris/* func */ 11560573Skris 11660573SkrisSession *session_new(void); 117215116Sdesvoid session_set_fds(Session *, int, int, int, int, int); 118126277Sdesvoid session_pty_cleanup(Session *); 11992559Sdesvoid session_proctitle(Session *); 12092559Sdesint session_setup_x11fwd(Session *); 121181111Sdesint do_exec_pty(Session *, const char *); 122181111Sdesint do_exec_no_pty(Session *, const char *); 123181111Sdesint do_exec(Session *, const char *); 12492559Sdesvoid do_login(Session *, const char *); 12598941Sdes#ifdef LOGIN_NEEDS_UTMPX 12698941Sdesstatic void do_pre_login(Session *s); 12798941Sdes#endif 12892559Sdesvoid do_child(Session *, const char *); 12976262Sgreenvoid do_motd(void); 13092559Sdesint check_quietlogin(Session *, const char *); 13160573Skris 13292559Sdesstatic void do_authenticated1(Authctxt *); 13392559Sdesstatic void do_authenticated2(Authctxt *); 13460573Skris 13592559Sdesstatic int session_pty_req(Session *); 13692559Sdes 13760573Skris/* import */ 13860573Skrisextern ServerOptions options; 13960573Skrisextern char *__progname; 14060573Skrisextern int log_stderr; 14160573Skrisextern int debug_flag; 14276262Sgreenextern u_int utmp_len; 14365674Skrisextern int startup_pipe; 14476262Sgreenextern void destroy_sensitive_data(void); 145124211Sdesextern Buffer loginmsg; 14665674Skris 14765674Skris/* original command from peer. */ 14892559Sdesconst char *original_command = NULL; 14965674Skris 15060573Skris/* data */ 151181111Sdesstatic int sessions_first_unused = -1; 152181111Sdesstatic int sessions_nalloc = 0; 153181111Sdesstatic Session *sessions = NULL; 15460573Skris 155204917Sdes#define SUBSYSTEM_NONE 0 156204917Sdes#define SUBSYSTEM_EXT 1 157204917Sdes#define SUBSYSTEM_INT_SFTP 2 158204917Sdes#define SUBSYSTEM_INT_SFTP_ERROR 3 159181111Sdes 16065674Skris#ifdef HAVE_LOGIN_CAP 16198684Sdeslogin_cap_t *lc; 16265674Skris#endif 16360573Skris 164126277Sdesstatic int is_child = 0; 165296781Sdesstatic int in_chroot = 0; 166126277Sdes 16798684Sdes/* Name and directory of socket for authentication agent forwarding. */ 16898684Sdesstatic char *auth_sock_name = NULL; 16998684Sdesstatic char *auth_sock_dir = NULL; 17098684Sdes 17198684Sdes/* removes the agent forwarding socket */ 17298684Sdes 17398684Sdesstatic void 174126277Sdesauth_sock_cleanup_proc(struct passwd *pw) 17598684Sdes{ 17698684Sdes if (auth_sock_name != NULL) { 17798684Sdes temporarily_use_uid(pw); 17898684Sdes unlink(auth_sock_name); 17998684Sdes rmdir(auth_sock_dir); 18098684Sdes auth_sock_name = NULL; 18198684Sdes restore_uid(); 18298684Sdes } 18398684Sdes} 18498684Sdes 18598684Sdesstatic int 18698684Sdesauth_input_request_forwarding(struct passwd * pw) 18798684Sdes{ 18898684Sdes Channel *nc; 189181111Sdes int sock = -1; 19098684Sdes 19198684Sdes if (auth_sock_name != NULL) { 19298684Sdes error("authentication forwarding requested twice."); 19398684Sdes return 0; 19498684Sdes } 19598684Sdes 19698684Sdes /* Temporarily drop privileged uid for mkdir/bind. */ 19798684Sdes temporarily_use_uid(pw); 19898684Sdes 19998684Sdes /* Allocate a buffer for the socket name, and format the name. */ 200181111Sdes auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX"); 20198684Sdes 20298684Sdes /* Create private directory for socket */ 20398684Sdes if (mkdtemp(auth_sock_dir) == NULL) { 20498684Sdes packet_send_debug("Agent forwarding disabled: " 20598684Sdes "mkdtemp() failed: %.100s", strerror(errno)); 20698684Sdes restore_uid(); 207255767Sdes free(auth_sock_dir); 20898684Sdes auth_sock_dir = NULL; 209181111Sdes goto authsock_err; 21098684Sdes } 21198684Sdes 212181111Sdes xasprintf(&auth_sock_name, "%s/agent.%ld", 213181111Sdes auth_sock_dir, (long) getpid()); 214181111Sdes 215295367Sdes /* Start a Unix listener on auth_sock_name. */ 216295367Sdes sock = unix_listener(auth_sock_name, SSH_LISTEN_BACKLOG, 0); 21798684Sdes 21898684Sdes /* Restore the privileged uid. */ 21998684Sdes restore_uid(); 22098684Sdes 221295367Sdes /* Check for socket/bind/listen failure. */ 222295367Sdes if (sock < 0) 223181111Sdes goto authsock_err; 22498684Sdes 225294693Sdes /* Allocate a channel for the authentication agent socket. */ 22698684Sdes nc = channel_new("auth socket", 22798684Sdes SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, 22898684Sdes CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 229124211Sdes 0, "auth socket", 1); 230192595Sdes nc->path = xstrdup(auth_sock_name); 23198684Sdes return 1; 232181111Sdes 233181111Sdes authsock_err: 234255767Sdes free(auth_sock_name); 235181111Sdes if (auth_sock_dir != NULL) { 236181111Sdes rmdir(auth_sock_dir); 237255767Sdes free(auth_sock_dir); 238181111Sdes } 239181111Sdes if (sock != -1) 240181111Sdes close(sock); 241181111Sdes auth_sock_name = NULL; 242181111Sdes auth_sock_dir = NULL; 243181111Sdes return 0; 24498684Sdes} 24598684Sdes 246126277Sdesstatic void 247126277Sdesdisplay_loginmsg(void) 248126277Sdes{ 249149753Sdes if (buffer_len(&loginmsg) > 0) { 250149753Sdes buffer_append(&loginmsg, "\0", 1); 251149753Sdes printf("%s", (char *)buffer_ptr(&loginmsg)); 252149753Sdes buffer_clear(&loginmsg); 253149753Sdes } 254126277Sdes} 25598684Sdes 25676262Sgreenvoid 25776262Sgreendo_authenticated(Authctxt *authctxt) 25876262Sgreen{ 259113911Sdes setproctitle("%s", authctxt->pw->pw_name); 260113911Sdes 26176262Sgreen /* setup the channel layer */ 262295367Sdes /* XXX - streamlocal? */ 263248619Sdes if (no_port_forwarding_flag || 264248619Sdes (options.allow_tcp_forwarding & FORWARD_LOCAL) == 0) 265248619Sdes channel_disable_adm_local_opens(); 266248619Sdes else 26776262Sgreen channel_permit_all_opens(); 26876262Sgreen 269204917Sdes auth_debug_send(); 270204917Sdes 27176262Sgreen if (compat20) 27276262Sgreen do_authenticated2(authctxt); 27376262Sgreen else 27476262Sgreen do_authenticated1(authctxt); 27577925Sgreen 276126277Sdes do_cleanup(authctxt); 27776262Sgreen} 27876262Sgreen 279296781Sdes/* Check untrusted xauth strings for metacharacters */ 280296781Sdesstatic int 281296781Sdesxauth_valid_string(const char *s) 282296781Sdes{ 283296781Sdes size_t i; 284296781Sdes 285296781Sdes for (i = 0; s[i] != '\0'; i++) { 286296781Sdes if (!isalnum((u_char)s[i]) && 287296781Sdes s[i] != '.' && s[i] != ':' && s[i] != '/' && 288296781Sdes s[i] != '-' && s[i] != '_') 289296781Sdes return 0; 290296781Sdes } 291296781Sdes return 1; 292296781Sdes} 293296781Sdes 29460573Skris/* 29560573Skris * Prepares for an interactive session. This is called after the user has 29660573Skris * been successfully authenticated. During this message exchange, pseudo 29760573Skris * terminals are allocated, X11, TCP/IP, and authentication agent forwardings 29860573Skris * are requested, etc. 29960573Skris */ 30092559Sdesstatic void 30176262Sgreendo_authenticated1(Authctxt *authctxt) 30260573Skris{ 30360573Skris Session *s; 30476262Sgreen char *command; 30592559Sdes int success, type, screen_flag; 30699063Sdes int enable_compression_after_reply = 0; 30799063Sdes u_int proto_len, data_len, dlen, compression_level = 0; 30860573Skris 30960573Skris s = session_new(); 310147005Sdes if (s == NULL) { 311147005Sdes error("no more sessions"); 312147005Sdes return; 313147005Sdes } 31492559Sdes s->authctxt = authctxt; 31576262Sgreen s->pw = authctxt->pw; 31660573Skris 31760573Skris /* 31860573Skris * We stay in this loop until the client requests to execute a shell 31960573Skris * or a command. 32060573Skris */ 32160573Skris for (;;) { 32276262Sgreen success = 0; 32360573Skris 32460573Skris /* Get a packet from the client. */ 32592559Sdes type = packet_read(); 32660573Skris 32760573Skris /* Process the packet. */ 32860573Skris switch (type) { 32960573Skris case SSH_CMSG_REQUEST_COMPRESSION: 33060573Skris compression_level = packet_get_int(); 33192559Sdes packet_check_eom(); 33260573Skris if (compression_level < 1 || compression_level > 9) { 333137019Sdes packet_send_debug("Received invalid compression level %d.", 33492559Sdes compression_level); 33560573Skris break; 33660573Skris } 337149753Sdes if (options.compression == COMP_NONE) { 33898684Sdes debug2("compression disabled"); 33998684Sdes break; 34098684Sdes } 34160573Skris /* Enable compression after we have responded with SUCCESS. */ 34260573Skris enable_compression_after_reply = 1; 34360573Skris success = 1; 34460573Skris break; 34560573Skris 34660573Skris case SSH_CMSG_REQUEST_PTY: 34792559Sdes success = session_pty_req(s); 34860573Skris break; 34960573Skris 35060573Skris case SSH_CMSG_X11_REQUEST_FORWARDING: 35160573Skris s->auth_proto = packet_get_string(&proto_len); 35260573Skris s->auth_data = packet_get_string(&data_len); 35360573Skris 35476262Sgreen screen_flag = packet_get_protocol_flags() & 35576262Sgreen SSH_PROTOFLAG_SCREEN_NUMBER; 35676262Sgreen debug2("SSH_PROTOFLAG_SCREEN_NUMBER: %d", screen_flag); 35776262Sgreen 35876262Sgreen if (packet_remaining() == 4) { 35976262Sgreen if (!screen_flag) 36076262Sgreen debug2("Buggy client: " 36176262Sgreen "X11 screen flag missing"); 36260573Skris s->screen = packet_get_int(); 36376262Sgreen } else { 36460573Skris s->screen = 0; 36576262Sgreen } 36692559Sdes packet_check_eom(); 367296781Sdes if (xauth_valid_string(s->auth_proto) && 368296781Sdes xauth_valid_string(s->auth_data)) 369296781Sdes success = session_setup_x11fwd(s); 370296781Sdes else { 371296781Sdes success = 0; 372296781Sdes error("Invalid X11 forwarding data"); 373296781Sdes } 37492559Sdes if (!success) { 375255767Sdes free(s->auth_proto); 376255767Sdes free(s->auth_data); 37792559Sdes s->auth_proto = NULL; 37892559Sdes s->auth_data = NULL; 37960573Skris } 38060573Skris break; 38160573Skris 38260573Skris case SSH_CMSG_AGENT_REQUEST_FORWARDING: 383181111Sdes if (!options.allow_agent_forwarding || 384181111Sdes no_agent_forwarding_flag || compat13) { 38560573Skris debug("Authentication agent forwarding not permitted for this authentication."); 38660573Skris break; 38760573Skris } 38860573Skris debug("Received authentication agent forwarding request."); 38976262Sgreen success = auth_input_request_forwarding(s->pw); 39060573Skris break; 39160573Skris 39260573Skris case SSH_CMSG_PORT_FORWARD_REQUEST: 39360573Skris if (no_port_forwarding_flag) { 39460573Skris debug("Port forwarding not permitted for this authentication."); 39560573Skris break; 39660573Skris } 397248619Sdes if (!(options.allow_tcp_forwarding & FORWARD_REMOTE)) { 39869591Sgreen debug("Port forwarding not permitted."); 39969591Sgreen break; 40069591Sgreen } 40160573Skris debug("Received TCP/IP port forwarding request."); 402162856Sdes if (channel_input_port_forward_request(s->pw->pw_uid == 0, 403295367Sdes &options.fwd_opts) < 0) { 404162856Sdes debug("Port forwarding failed."); 405162856Sdes break; 406162856Sdes } 40760573Skris success = 1; 40860573Skris break; 40960573Skris 41060573Skris case SSH_CMSG_MAX_PACKET_SIZE: 41160573Skris if (packet_set_maxsize(packet_get_int()) > 0) 41260573Skris success = 1; 41360573Skris break; 41460573Skris 41560573Skris case SSH_CMSG_EXEC_SHELL: 41660573Skris case SSH_CMSG_EXEC_CMD: 41760573Skris if (type == SSH_CMSG_EXEC_CMD) { 41860573Skris command = packet_get_string(&dlen); 41960573Skris debug("Exec command '%.500s'", command); 420181111Sdes if (do_exec(s, command) != 0) 421181111Sdes packet_disconnect( 422181111Sdes "command execution failed"); 423255767Sdes free(command); 42460573Skris } else { 425181111Sdes if (do_exec(s, NULL) != 0) 426181111Sdes packet_disconnect( 427181111Sdes "shell execution failed"); 42860573Skris } 42992559Sdes packet_check_eom(); 43092559Sdes session_close(s); 43160573Skris return; 43260573Skris 43360573Skris default: 43460573Skris /* 43560573Skris * Any unknown messages in this phase are ignored, 43660573Skris * and a failure message is returned. 43760573Skris */ 438124211Sdes logit("Unknown packet type received after authentication: %d", type); 43960573Skris } 44060573Skris packet_start(success ? SSH_SMSG_SUCCESS : SSH_SMSG_FAILURE); 44160573Skris packet_send(); 44260573Skris packet_write_wait(); 44360573Skris 44460573Skris /* Enable compression now that we have replied if appropriate. */ 44560573Skris if (enable_compression_after_reply) { 44660573Skris enable_compression_after_reply = 0; 44760573Skris packet_start_compression(compression_level); 44860573Skris } 44960573Skris } 45060573Skris} 45160573Skris 452262566Sdes#define USE_PIPES 1 45360573Skris/* 45460573Skris * This is called to fork and execute a command when we have no tty. This 45560573Skris * will call do_child from the child, and server_loop from the parent after 45660573Skris * setting up file descriptors and such. 45760573Skris */ 458181111Sdesint 45976262Sgreendo_exec_no_pty(Session *s, const char *command) 46060573Skris{ 46198684Sdes pid_t pid; 46260573Skris 46360573Skris#ifdef USE_PIPES 46460573Skris int pin[2], pout[2], perr[2]; 465181111Sdes 466215116Sdes if (s == NULL) 467215116Sdes fatal("do_exec_no_pty: no session"); 468215116Sdes 46960573Skris /* Allocate pipes for communicating with the program. */ 470181111Sdes if (pipe(pin) < 0) { 471181111Sdes error("%s: pipe in: %.100s", __func__, strerror(errno)); 472181111Sdes return -1; 473181111Sdes } 474181111Sdes if (pipe(pout) < 0) { 475181111Sdes error("%s: pipe out: %.100s", __func__, strerror(errno)); 476181111Sdes close(pin[0]); 477181111Sdes close(pin[1]); 478181111Sdes return -1; 479181111Sdes } 480181111Sdes if (pipe(perr) < 0) { 481215116Sdes error("%s: pipe err: %.100s", __func__, 482215116Sdes strerror(errno)); 483181111Sdes close(pin[0]); 484181111Sdes close(pin[1]); 485181111Sdes close(pout[0]); 486181111Sdes close(pout[1]); 487181111Sdes return -1; 488181111Sdes } 489181111Sdes#else 49060573Skris int inout[2], err[2]; 491181111Sdes 492215116Sdes if (s == NULL) 493215116Sdes fatal("do_exec_no_pty: no session"); 494215116Sdes 49560573Skris /* Uses socket pairs to communicate with the program. */ 496181111Sdes if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0) { 497181111Sdes error("%s: socketpair #1: %.100s", __func__, strerror(errno)); 498181111Sdes return -1; 499181111Sdes } 500181111Sdes if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) { 501215116Sdes error("%s: socketpair #2: %.100s", __func__, 502215116Sdes strerror(errno)); 503181111Sdes close(inout[0]); 504181111Sdes close(inout[1]); 505181111Sdes return -1; 506181111Sdes } 507181111Sdes#endif 508181111Sdes 50960573Skris session_proctitle(s); 51060573Skris 51160573Skris /* Fork the child. */ 512181111Sdes switch ((pid = fork())) { 513181111Sdes case -1: 514181111Sdes error("%s: fork: %.100s", __func__, strerror(errno)); 515181111Sdes#ifdef USE_PIPES 516181111Sdes close(pin[0]); 517181111Sdes close(pin[1]); 518181111Sdes close(pout[0]); 519181111Sdes close(pout[1]); 520181111Sdes close(perr[0]); 521181111Sdes close(perr[1]); 522181111Sdes#else 523181111Sdes close(inout[0]); 524181111Sdes close(inout[1]); 525181111Sdes close(err[0]); 526181111Sdes close(err[1]); 527181111Sdes#endif 528181111Sdes return -1; 529181111Sdes case 0: 530126277Sdes is_child = 1; 531106130Sdes 53260573Skris /* Child. Reinitialize the log since the pid has changed. */ 533181111Sdes log_init(__progname, options.log_level, 534181111Sdes options.log_facility, log_stderr); 53560573Skris 53660573Skris /* 53760573Skris * Create a new session and process group since the 4.4BSD 53860573Skris * setlogin() affects the entire process group. 53960573Skris */ 54060573Skris if (setsid() < 0) 54160573Skris error("setsid failed: %.100s", strerror(errno)); 54260573Skris 54360573Skris#ifdef USE_PIPES 54460573Skris /* 54560573Skris * Redirect stdin. We close the parent side of the socket 54660573Skris * pair, and make the child side the standard input. 54760573Skris */ 54860573Skris close(pin[1]); 54960573Skris if (dup2(pin[0], 0) < 0) 55060573Skris perror("dup2 stdin"); 55160573Skris close(pin[0]); 55260573Skris 55360573Skris /* Redirect stdout. */ 55460573Skris close(pout[0]); 55560573Skris if (dup2(pout[1], 1) < 0) 55660573Skris perror("dup2 stdout"); 55760573Skris close(pout[1]); 55860573Skris 55960573Skris /* Redirect stderr. */ 56060573Skris close(perr[0]); 56160573Skris if (dup2(perr[1], 2) < 0) 56260573Skris perror("dup2 stderr"); 56360573Skris close(perr[1]); 564181111Sdes#else 56560573Skris /* 56660573Skris * Redirect stdin, stdout, and stderr. Stdin and stdout will 56760573Skris * use the same socket, as some programs (particularly rdist) 56860573Skris * seem to depend on it. 56960573Skris */ 57060573Skris close(inout[1]); 57160573Skris close(err[1]); 57260573Skris if (dup2(inout[0], 0) < 0) /* stdin */ 57360573Skris perror("dup2 stdin"); 574181111Sdes if (dup2(inout[0], 1) < 0) /* stdout (same as stdin) */ 57560573Skris perror("dup2 stdout"); 576181111Sdes close(inout[0]); 57760573Skris if (dup2(err[0], 2) < 0) /* stderr */ 57860573Skris perror("dup2 stderr"); 579181111Sdes close(err[0]); 580181111Sdes#endif 58160573Skris 582181111Sdes 583106130Sdes#ifdef _UNICOS 584106130Sdes cray_init_job(s->pw); /* set up cray jid and tmpdir */ 585106130Sdes#endif 586106130Sdes 58760573Skris /* Do processing for the child (exec command etc). */ 58876262Sgreen do_child(s, command); 58960573Skris /* NOTREACHED */ 590181111Sdes default: 591181111Sdes break; 59260573Skris } 593181111Sdes 594106130Sdes#ifdef _UNICOS 595106130Sdes signal(WJSIGNAL, cray_job_termination_handler); 596106130Sdes#endif /* _UNICOS */ 59798941Sdes#ifdef HAVE_CYGWIN 598197679Sdes cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); 59998941Sdes#endif 600181111Sdes 60160573Skris s->pid = pid; 60276262Sgreen /* Set interactive/non-interactive mode. */ 603221420Sdes packet_set_interactive(s->display != NULL, 604221420Sdes options.ip_qos_interactive, options.ip_qos_bulk); 605181111Sdes 606181111Sdes /* 607181111Sdes * Clear loginmsg, since it's the child's responsibility to display 608181111Sdes * it to the user, otherwise multiple sessions may accumulate 609181111Sdes * multiple copies of the login messages. 610181111Sdes */ 611181111Sdes buffer_clear(&loginmsg); 612181111Sdes 61360573Skris#ifdef USE_PIPES 61460573Skris /* We are the parent. Close the child sides of the pipes. */ 61560573Skris close(pin[0]); 61660573Skris close(pout[1]); 61760573Skris close(perr[1]); 61860573Skris 61960573Skris if (compat20) { 620215116Sdes session_set_fds(s, pin[1], pout[0], perr[0], 621215116Sdes s->is_subsystem, 0); 62260573Skris } else { 62360573Skris /* Enter the interactive session. */ 62460573Skris server_loop(pid, pin[1], pout[0], perr[0]); 62576262Sgreen /* server_loop has closed pin[1], pout[0], and perr[0]. */ 62660573Skris } 627181111Sdes#else 62860573Skris /* We are the parent. Close the child sides of the socket pairs. */ 62960573Skris close(inout[0]); 63060573Skris close(err[0]); 63160573Skris 63260573Skris /* 63360573Skris * Enter the interactive session. Note: server_loop must be able to 63460573Skris * handle the case that fdin and fdout are the same. 63560573Skris */ 63660573Skris if (compat20) { 637215116Sdes session_set_fds(s, inout[1], inout[1], err[1], 638215116Sdes s->is_subsystem, 0); 63960573Skris } else { 64060573Skris server_loop(pid, inout[1], inout[1], err[1]); 64160573Skris /* server_loop has closed inout[1] and err[1]. */ 64260573Skris } 643181111Sdes#endif 644181111Sdes return 0; 64560573Skris} 64660573Skris 64760573Skris/* 64860573Skris * This is called to fork and execute a command when we have a tty. This 64960573Skris * will call do_child from the child, and server_loop from the parent after 65060573Skris * setting up file descriptors, controlling tty, updating wtmp, utmp, 65160573Skris * lastlog, and other such operations. 65260573Skris */ 653181111Sdesint 65476262Sgreendo_exec_pty(Session *s, const char *command) 65560573Skris{ 65660573Skris int fdout, ptyfd, ttyfd, ptymaster; 65760573Skris pid_t pid; 65860573Skris 65960573Skris if (s == NULL) 66060573Skris fatal("do_exec_pty: no session"); 66160573Skris ptyfd = s->ptyfd; 66260573Skris ttyfd = s->ttyfd; 66360573Skris 664181111Sdes /* 665181111Sdes * Create another descriptor of the pty master side for use as the 666181111Sdes * standard input. We could use the original descriptor, but this 667181111Sdes * simplifies code in server_loop. The descriptor is bidirectional. 668181111Sdes * Do this before forking (and cleanup in the child) so as to 669181111Sdes * detect and gracefully fail out-of-fd conditions. 670181111Sdes */ 671181111Sdes if ((fdout = dup(ptyfd)) < 0) { 672181111Sdes error("%s: dup #1: %s", __func__, strerror(errno)); 673181111Sdes close(ttyfd); 674181111Sdes close(ptyfd); 675181111Sdes return -1; 676124211Sdes } 677181111Sdes /* we keep a reference to the pty master */ 678181111Sdes if ((ptymaster = dup(ptyfd)) < 0) { 679181111Sdes error("%s: dup #2: %s", __func__, strerror(errno)); 680181111Sdes close(ttyfd); 681181111Sdes close(ptyfd); 682181111Sdes close(fdout); 683181111Sdes return -1; 684181111Sdes } 68569591Sgreen 68660573Skris /* Fork the child. */ 687181111Sdes switch ((pid = fork())) { 688181111Sdes case -1: 689181111Sdes error("%s: fork: %.100s", __func__, strerror(errno)); 690181111Sdes close(fdout); 691181111Sdes close(ptymaster); 692181111Sdes close(ttyfd); 693181111Sdes close(ptyfd); 694181111Sdes return -1; 695181111Sdes case 0: 696126277Sdes is_child = 1; 69792559Sdes 698181111Sdes close(fdout); 699181111Sdes close(ptymaster); 700181111Sdes 70165674Skris /* Child. Reinitialize the log because the pid has changed. */ 702181111Sdes log_init(__progname, options.log_level, 703181111Sdes options.log_facility, log_stderr); 70460573Skris /* Close the master side of the pseudo tty. */ 70560573Skris close(ptyfd); 70660573Skris 70760573Skris /* Make the pseudo tty our controlling tty. */ 70860573Skris pty_make_controlling_tty(&ttyfd, s->tty); 70960573Skris 71092559Sdes /* Redirect stdin/stdout/stderr from the pseudo tty. */ 71192559Sdes if (dup2(ttyfd, 0) < 0) 71292559Sdes error("dup2 stdin: %s", strerror(errno)); 71392559Sdes if (dup2(ttyfd, 1) < 0) 71492559Sdes error("dup2 stdout: %s", strerror(errno)); 71592559Sdes if (dup2(ttyfd, 2) < 0) 71692559Sdes error("dup2 stderr: %s", strerror(errno)); 71760573Skris 71860573Skris /* Close the extra descriptor for the pseudo tty. */ 71960573Skris close(ttyfd); 72060573Skris 72165674Skris /* record login, etc. similar to login(1) */ 72298941Sdes#ifndef HAVE_OSF_SIA 723106130Sdes if (!(options.use_login && command == NULL)) { 724106130Sdes#ifdef _UNICOS 725106130Sdes cray_init_job(s->pw); /* set up cray jid and tmpdir */ 726106130Sdes#endif /* _UNICOS */ 72776262Sgreen do_login(s, command); 728106130Sdes } 72998941Sdes# ifdef LOGIN_NEEDS_UTMPX 73098941Sdes else 73198941Sdes do_pre_login(s); 73298941Sdes# endif 73398941Sdes#endif 734181111Sdes /* 735181111Sdes * Do common processing for the child, such as execing 736181111Sdes * the command. 737181111Sdes */ 738197679Sdes do_child(s, command); 739197679Sdes /* NOTREACHED */ 740181111Sdes default: 741181111Sdes break; 742181111Sdes } 74360573Skris 744106130Sdes#ifdef _UNICOS 745106130Sdes signal(WJSIGNAL, cray_job_termination_handler); 746106130Sdes#endif /* _UNICOS */ 74798941Sdes#ifdef HAVE_CYGWIN 748197679Sdes cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); 74998941Sdes#endif 750181111Sdes 75160573Skris s->pid = pid; 75260573Skris 75360573Skris /* Parent. Close the slave side of the pseudo tty. */ 75460573Skris close(ttyfd); 75560573Skris 756181111Sdes /* Enter interactive session. */ 75760573Skris s->ptymaster = ptymaster; 758221420Sdes packet_set_interactive(1, 759221420Sdes options.ip_qos_interactive, options.ip_qos_bulk); 76060573Skris if (compat20) { 761215116Sdes session_set_fds(s, ptyfd, fdout, -1, 1, 1); 76260573Skris } else { 76360573Skris server_loop(pid, ptyfd, fdout, -1); 76460573Skris /* server_loop _has_ closed ptyfd and fdout. */ 76560573Skris } 766181111Sdes return 0; 76760573Skris} 76860573Skris 76998941Sdes#ifdef LOGIN_NEEDS_UTMPX 77098941Sdesstatic void 77198941Sdesdo_pre_login(Session *s) 77298941Sdes{ 773323124Sdes struct ssh *ssh = active_state; /* XXX */ 77498941Sdes socklen_t fromlen; 77598941Sdes struct sockaddr_storage from; 77698941Sdes pid_t pid = getpid(); 77798941Sdes 77898941Sdes /* 77998941Sdes * Get IP address of client. If the connection is not a socket, let 78098941Sdes * the address be 0.0.0.0. 78198941Sdes */ 78298941Sdes memset(&from, 0, sizeof(from)); 783103134Sume fromlen = sizeof(from); 78498941Sdes if (packet_connection_is_on_socket()) { 78598941Sdes if (getpeername(packet_get_connection_in(), 786162856Sdes (struct sockaddr *)&from, &fromlen) < 0) { 78798941Sdes debug("getpeername: %.100s", strerror(errno)); 788126277Sdes cleanup_exit(255); 78998941Sdes } 79098941Sdes } 79198941Sdes 79298941Sdes record_utmp_only(pid, s->tty, s->pw->pw_name, 793323124Sdes session_get_remote_name_or_ip(ssh, utmp_len, options.use_dns), 794103134Sume (struct sockaddr *)&from, fromlen); 79598941Sdes} 79698941Sdes#endif 79798941Sdes 79892559Sdes/* 79992559Sdes * This is called to fork and execute a command. If another command is 80092559Sdes * to be forced, execute that instead. 80192559Sdes */ 802181111Sdesint 80392559Sdesdo_exec(Session *s, const char *command) 80492559Sdes{ 805323124Sdes struct ssh *ssh = active_state; /* XXX */ 806181111Sdes int ret; 807296781Sdes const char *forced = NULL, *tty = NULL; 808296781Sdes char session_type[1024]; 809181111Sdes 810162856Sdes if (options.adm_forced_command) { 81192559Sdes original_command = command; 812162856Sdes command = options.adm_forced_command; 813262566Sdes forced = "(config)"; 814162856Sdes } else if (forced_command) { 815162856Sdes original_command = command; 81692559Sdes command = forced_command; 817262566Sdes forced = "(key-option)"; 818262566Sdes } 819262566Sdes if (forced != NULL) { 820204917Sdes if (IS_INTERNAL_SFTP(command)) { 821204917Sdes s->is_subsystem = s->is_subsystem ? 822204917Sdes SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR; 823204917Sdes } else if (s->is_subsystem) 824181111Sdes s->is_subsystem = SUBSYSTEM_EXT; 825262566Sdes snprintf(session_type, sizeof(session_type), 826262566Sdes "forced-command %s '%.900s'", forced, command); 827262566Sdes } else if (s->is_subsystem) { 828262566Sdes snprintf(session_type, sizeof(session_type), 829262566Sdes "subsystem '%.900s'", s->subsys); 830262566Sdes } else if (command == NULL) { 831262566Sdes snprintf(session_type, sizeof(session_type), "shell"); 832262566Sdes } else { 833262566Sdes /* NB. we don't log unforced commands to preserve privacy */ 834262566Sdes snprintf(session_type, sizeof(session_type), "command"); 83592559Sdes } 83692559Sdes 837262566Sdes if (s->ttyfd != -1) { 838262566Sdes tty = s->tty; 839262566Sdes if (strncmp(tty, "/dev/", 5) == 0) 840262566Sdes tty += 5; 841262566Sdes } 842262566Sdes 843296781Sdes verbose("Starting session: %s%s%s for %s from %.200s port %d id %d", 844262566Sdes session_type, 845262566Sdes tty == NULL ? "" : " on ", 846262566Sdes tty == NULL ? "" : tty, 847262566Sdes s->pw->pw_name, 848323124Sdes ssh_remote_ipaddr(ssh), 849323124Sdes ssh_remote_port(ssh), 850296781Sdes s->self); 851262566Sdes 852147005Sdes#ifdef SSH_AUDIT_EVENTS 853147005Sdes if (command != NULL) 854147005Sdes PRIVSEP(audit_run_command(command)); 855147005Sdes else if (s->ttyfd == -1) { 856147005Sdes char *shell = s->pw->pw_shell; 857147005Sdes 858147005Sdes if (shell[0] == '\0') /* empty shell means /bin/sh */ 859147005Sdes shell =_PATH_BSHELL; 860147005Sdes PRIVSEP(audit_run_command(shell)); 861124211Sdes } 862124211Sdes#endif 86392559Sdes if (s->ttyfd != -1) 864181111Sdes ret = do_exec_pty(s, command); 86592559Sdes else 866181111Sdes ret = do_exec_no_pty(s, command); 86792559Sdes 86892559Sdes original_command = NULL; 869137019Sdes 870137019Sdes /* 871137019Sdes * Clear loginmsg: it's the child's responsibility to display 872137019Sdes * it to the user, otherwise multiple sessions may accumulate 873137019Sdes * multiple copies of the login messages. 874137019Sdes */ 875137019Sdes buffer_clear(&loginmsg); 876181111Sdes 877181111Sdes return ret; 87892559Sdes} 87992559Sdes 88065674Skris/* administrative, login(1)-like work */ 88176262Sgreenvoid 88265674Skrisdo_login(Session *s, const char *command) 88365674Skris{ 884323124Sdes struct ssh *ssh = active_state; /* XXX */ 88565674Skris socklen_t fromlen; 88665674Skris struct sockaddr_storage from; 88765674Skris struct passwd * pw = s->pw; 88865674Skris pid_t pid = getpid(); 88965674Skris 89065674Skris /* 89165674Skris * Get IP address of client. If the connection is not a socket, let 89265674Skris * the address be 0.0.0.0. 89365674Skris */ 89465674Skris memset(&from, 0, sizeof(from)); 895103134Sume fromlen = sizeof(from); 89665674Skris if (packet_connection_is_on_socket()) { 89765674Skris if (getpeername(packet_get_connection_in(), 898197679Sdes (struct sockaddr *)&from, &fromlen) < 0) { 89965674Skris debug("getpeername: %.100s", strerror(errno)); 900126277Sdes cleanup_exit(255); 90165674Skris } 90265674Skris } 90365674Skris 90498941Sdes /* Record that there was a login on that tty from the remote host. */ 90598941Sdes if (!use_privsep) 90698941Sdes record_login(pid, s->tty, pw->pw_name, pw->pw_uid, 907323124Sdes session_get_remote_name_or_ip(ssh, utmp_len, 908124211Sdes options.use_dns), 909103134Sume (struct sockaddr *)&from, fromlen); 91098941Sdes 91169591Sgreen#ifdef USE_PAM 91269591Sgreen /* 91369591Sgreen * If password change is needed, do it now. 91469591Sgreen * This needs to occur before the ~/.hushlogin check. 91569591Sgreen */ 916126277Sdes if (options.use_pam && !use_privsep && s->authctxt->force_pwchange) { 917126277Sdes display_loginmsg(); 91869591Sgreen do_pam_chauthtok(); 919126277Sdes s->authctxt->force_pwchange = 0; 920124211Sdes /* XXX - signal [net] parent to enable forwardings */ 92169591Sgreen } 92269591Sgreen#endif 92365674Skris 92498941Sdes if (check_quietlogin(s, command)) 92598941Sdes return; 92698684Sdes 927126277Sdes display_loginmsg(); 928106130Sdes 92998941Sdes do_motd(); 93076262Sgreen} 93176262Sgreen 93276262Sgreen/* 93376262Sgreen * Display the message of the day. 93476262Sgreen */ 93576262Sgreenvoid 93676262Sgreendo_motd(void) 93776262Sgreen{ 93876262Sgreen FILE *f; 93976262Sgreen char buf[256]; 94076262Sgreen 94176262Sgreen if (options.print_motd) { 94265674Skris#ifdef HAVE_LOGIN_CAP 94365674Skris f = fopen(login_getcapstr(lc, "welcome", "/etc/motd", 94465674Skris "/etc/motd"), "r"); 94592559Sdes#else 94665674Skris f = fopen("/etc/motd", "r"); 94792559Sdes#endif 94865674Skris if (f) { 94965674Skris while (fgets(buf, sizeof(buf), f)) 95065674Skris fputs(buf, stdout); 95165674Skris fclose(f); 95265674Skris } 95365674Skris } 95476262Sgreen} 95565674Skris 95692559Sdes 95776262Sgreen/* 95876262Sgreen * Check for quiet login, either .hushlogin or command given. 95976262Sgreen */ 96076262Sgreenint 96176262Sgreencheck_quietlogin(Session *s, const char *command) 96276262Sgreen{ 96376262Sgreen char buf[256]; 96492559Sdes struct passwd *pw = s->pw; 96576262Sgreen struct stat st; 96676262Sgreen 96776262Sgreen /* Return 1 if .hushlogin exists or a command given. */ 96876262Sgreen if (command != NULL) 96976262Sgreen return 1; 97076262Sgreen snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir); 97165674Skris#ifdef HAVE_LOGIN_CAP 97276262Sgreen if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0) 97376262Sgreen return 1; 97476262Sgreen#else 97576262Sgreen if (stat(buf, &st) >= 0) 97676262Sgreen return 1; 97776262Sgreen#endif 97876262Sgreen return 0; 97965674Skris} 98065674Skris 98160573Skris/* 98260573Skris * Sets the value of the given variable in the environment. If the variable 983192595Sdes * already exists, its value is overridden. 98460573Skris */ 985124211Sdesvoid 98676262Sgreenchild_set_env(char ***envp, u_int *envsizep, const char *name, 98792559Sdes const char *value) 98860573Skris{ 989120161Snectar char **env; 990120161Snectar u_int envsize; 99176262Sgreen u_int i, namelen; 99260573Skris 993264377Sdes if (strchr(name, '=') != NULL) { 994264377Sdes error("Invalid environment variable \"%.100s\"", name); 995264377Sdes return; 996264377Sdes } 997264377Sdes 99860573Skris /* 999124211Sdes * If we're passed an uninitialized list, allocate a single null 1000124211Sdes * entry before continuing. 1001124211Sdes */ 1002124211Sdes if (*envp == NULL && *envsizep == 0) { 1003124211Sdes *envp = xmalloc(sizeof(char *)); 1004124211Sdes *envp[0] = NULL; 1005124211Sdes *envsizep = 1; 1006124211Sdes } 1007124211Sdes 1008124211Sdes /* 100960573Skris * Find the slot where the value should be stored. If the variable 101060573Skris * already exists, we reuse the slot; otherwise we append a new slot 101160573Skris * at the end of the array, expanding if necessary. 101260573Skris */ 101360573Skris env = *envp; 101460573Skris namelen = strlen(name); 101560573Skris for (i = 0; env[i]; i++) 101660573Skris if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=') 101760573Skris break; 101860573Skris if (env[i]) { 101960573Skris /* Reuse the slot. */ 1020255767Sdes free(env[i]); 102160573Skris } else { 102260573Skris /* New variable. Expand if necessary. */ 1023120161Snectar envsize = *envsizep; 1024120161Snectar if (i >= envsize - 1) { 1025120161Snectar if (envsize >= 1000) 1026120161Snectar fatal("child_set_env: too many env vars"); 1027120161Snectar envsize += 50; 1028295367Sdes env = (*envp) = xreallocarray(env, envsize, sizeof(char *)); 1029120161Snectar *envsizep = envsize; 103060573Skris } 103160573Skris /* Need to set the NULL pointer at end of array beyond the new slot. */ 103260573Skris env[i + 1] = NULL; 103360573Skris } 103460573Skris 103560573Skris /* Allocate space and format the variable in the appropriate slot. */ 103660573Skris env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1); 103760573Skris snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value); 103860573Skris} 103960573Skris 104060573Skris/* 104160573Skris * Reads environment variables from the given file and adds/overrides them 104260573Skris * into the environment. If the file does not exist, this does nothing. 104360573Skris * Otherwise, it must consist of empty lines, comments (line starts with '#') 104460573Skris * and assignments of the form name=value. No other forms are allowed. 104560573Skris */ 104692559Sdesstatic void 104776262Sgreenread_environment_file(char ***env, u_int *envsize, 104892559Sdes const char *filename) 104960573Skris{ 105060573Skris FILE *f; 105160573Skris char buf[4096]; 105260573Skris char *cp, *value; 105399063Sdes u_int lineno = 0; 105460573Skris 105560573Skris f = fopen(filename, "r"); 105660573Skris if (!f) 105760573Skris return; 105860573Skris 105960573Skris while (fgets(buf, sizeof(buf), f)) { 106099063Sdes if (++lineno > 1000) 106199063Sdes fatal("Too many lines in environment file %s", filename); 106260573Skris for (cp = buf; *cp == ' ' || *cp == '\t'; cp++) 106360573Skris ; 106460573Skris if (!*cp || *cp == '#' || *cp == '\n') 106560573Skris continue; 1066181111Sdes 1067181111Sdes cp[strcspn(cp, "\n")] = '\0'; 1068181111Sdes 106960573Skris value = strchr(cp, '='); 107060573Skris if (value == NULL) { 107199063Sdes fprintf(stderr, "Bad line %u in %.100s\n", lineno, 107299063Sdes filename); 107360573Skris continue; 107460573Skris } 107561203Skris /* 107661203Skris * Replace the equals sign by nul, and advance value to 107761203Skris * the value string. 107861203Skris */ 107960573Skris *value = '\0'; 108060573Skris value++; 108160573Skris child_set_env(env, envsize, cp, value); 108260573Skris } 108360573Skris fclose(f); 108460573Skris} 108560573Skris 1086124211Sdes#ifdef HAVE_ETC_DEFAULT_LOGIN 1087124211Sdes/* 1088124211Sdes * Return named variable from specified environment, or NULL if not present. 1089124211Sdes */ 1090124211Sdesstatic char * 1091124211Sdeschild_get_env(char **env, const char *name) 1092124211Sdes{ 1093124211Sdes int i; 1094124211Sdes size_t len; 1095124211Sdes 1096124211Sdes len = strlen(name); 1097124211Sdes for (i=0; env[i] != NULL; i++) 1098124211Sdes if (strncmp(name, env[i], len) == 0 && env[i][len] == '=') 1099124211Sdes return(env[i] + len + 1); 1100124211Sdes return NULL; 1101124211Sdes} 1102124211Sdes 1103124211Sdes/* 1104124211Sdes * Read /etc/default/login. 1105124211Sdes * We pick up the PATH (or SUPATH for root) and UMASK. 1106124211Sdes */ 1107124211Sdesstatic void 1108124211Sdesread_etc_default_login(char ***env, u_int *envsize, uid_t uid) 1109124211Sdes{ 1110124211Sdes char **tmpenv = NULL, *var; 1111124211Sdes u_int i, tmpenvsize = 0; 1112126277Sdes u_long mask; 1113124211Sdes 1114124211Sdes /* 1115124211Sdes * We don't want to copy the whole file to the child's environment, 1116124211Sdes * so we use a temporary environment and copy the variables we're 1117124211Sdes * interested in. 1118124211Sdes */ 1119124211Sdes read_environment_file(&tmpenv, &tmpenvsize, "/etc/default/login"); 1120124211Sdes 1121124211Sdes if (tmpenv == NULL) 1122124211Sdes return; 1123124211Sdes 1124124211Sdes if (uid == 0) 1125124211Sdes var = child_get_env(tmpenv, "SUPATH"); 1126124211Sdes else 1127124211Sdes var = child_get_env(tmpenv, "PATH"); 1128124211Sdes if (var != NULL) 1129124211Sdes child_set_env(env, envsize, "PATH", var); 1130126277Sdes 1131124211Sdes if ((var = child_get_env(tmpenv, "UMASK")) != NULL) 1132124211Sdes if (sscanf(var, "%5lo", &mask) == 1) 1133126277Sdes umask((mode_t)mask); 1134126277Sdes 1135124211Sdes for (i = 0; tmpenv[i] != NULL; i++) 1136255767Sdes free(tmpenv[i]); 1137255767Sdes free(tmpenv); 1138124211Sdes} 1139124211Sdes#endif /* HAVE_ETC_DEFAULT_LOGIN */ 1140124211Sdes 1141149753Sdesvoid 1142149753Sdescopy_environment(char **source, char ***env, u_int *envsize) 114369591Sgreen{ 114498941Sdes char *var_name, *var_val; 114569591Sgreen int i; 114669591Sgreen 114798941Sdes if (source == NULL) 114869591Sgreen return; 114998941Sdes 115098941Sdes for(i = 0; source[i] != NULL; i++) { 115198941Sdes var_name = xstrdup(source[i]); 115298941Sdes if ((var_val = strstr(var_name, "=")) == NULL) { 1153255767Sdes free(var_name); 115469591Sgreen continue; 115598941Sdes } 115698941Sdes *var_val++ = '\0'; 115769591Sgreen 115898941Sdes debug3("Copy environment: %s=%s", var_name, var_val); 115998941Sdes child_set_env(env, envsize, var_name, var_val); 1160126277Sdes 1161255767Sdes free(var_name); 116269591Sgreen } 116369591Sgreen} 116469591Sgreen 116592559Sdesstatic char ** 116698941Sdesdo_setup_env(Session *s, const char *shell) 116760573Skris{ 1168323124Sdes struct ssh *ssh = active_state; /* XXX */ 116960573Skris char buf[256]; 117092559Sdes u_int i, envsize; 1171162856Sdes char **env, *laddr; 1172162856Sdes struct passwd *pw = s->pw; 1173197679Sdes#if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN) 1174162856Sdes char *path = NULL; 1175162856Sdes#else 117699055Sdes extern char **environ; 117799055Sdes char **senv, **var; 117899055Sdes#endif 117960573Skris 118098941Sdes /* Initialize the environment. */ 118198941Sdes envsize = 100; 1182162856Sdes env = xcalloc(envsize, sizeof(char *)); 118398941Sdes env[0] = NULL; 118460573Skris 118598941Sdes#ifdef HAVE_CYGWIN 118698941Sdes /* 118798941Sdes * The Windows environment contains some setting which are 118898941Sdes * important for a running system. They must not be dropped. 118998941Sdes */ 1190147005Sdes { 1191147005Sdes char **p; 1192147005Sdes 1193147005Sdes p = fetch_windows_environment(); 1194147005Sdes copy_environment(p, &env, &envsize); 1195147005Sdes free_windows_environment(p); 1196147005Sdes } 119798941Sdes#endif 119898941Sdes 119999055Sdes if (getenv("TZ")) 120099055Sdes child_set_env(&env, &envsize, "TZ", getenv("TZ")); 1201124211Sdes 1202124211Sdes#ifdef GSSAPI 1203126277Sdes /* Allow any GSSAPI methods that we've used to alter 1204124211Sdes * the childs environment as they see fit 1205124211Sdes */ 1206124211Sdes ssh_gssapi_do_child(&env, &envsize); 1207124211Sdes#endif 1208124211Sdes 120960573Skris if (!options.use_login) { 121060573Skris /* Set basic environment. */ 1211137019Sdes for (i = 0; i < s->num_env; i++) 1212137019Sdes child_set_env(&env, &envsize, s->env[i].name, 1213137019Sdes s->env[i].val); 1214137019Sdes 121560573Skris child_set_env(&env, &envsize, "USER", pw->pw_name); 121660573Skris child_set_env(&env, &envsize, "LOGNAME", pw->pw_name); 1217113911Sdes#ifdef _AIX 1218113911Sdes child_set_env(&env, &envsize, "LOGIN", pw->pw_name); 1219113911Sdes#endif 122060573Skris child_set_env(&env, &envsize, "HOME", pw->pw_dir); 122199055Sdes snprintf(buf, sizeof buf, "%.200s/%.50s", 122299055Sdes _PATH_MAILDIR, pw->pw_name); 122399055Sdes child_set_env(&env, &envsize, "MAIL", buf); 122498941Sdes#ifdef HAVE_LOGIN_CAP 122599055Sdes child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); 122699055Sdes child_set_env(&env, &envsize, "TERM", "su"); 122799055Sdes senv = environ; 122899055Sdes environ = xmalloc(sizeof(char *)); 122999055Sdes *environ = NULL; 123099055Sdes (void) setusercontext(lc, pw, pw->pw_uid, 123199055Sdes LOGIN_SETENV|LOGIN_SETPATH); 123299055Sdes copy_environment(environ, &env, &envsize); 123399055Sdes for (var = environ; *var != NULL; ++var) 1234255767Sdes free(*var); 1235255767Sdes free(environ); 123699055Sdes environ = senv; 123798941Sdes#else /* HAVE_LOGIN_CAP */ 123898941Sdes# ifndef HAVE_CYGWIN 123998941Sdes /* 124098941Sdes * There's no standard path on Windows. The path contains 124198941Sdes * important components pointing to the system directories, 124298941Sdes * needed for loading shared libraries. So the path better 124398941Sdes * remains intact here. 124498941Sdes */ 1245124211Sdes# ifdef HAVE_ETC_DEFAULT_LOGIN 1246124211Sdes read_etc_default_login(&env, &envsize, pw->pw_uid); 1247124211Sdes path = child_get_env(env, "PATH"); 1248124211Sdes# endif /* HAVE_ETC_DEFAULT_LOGIN */ 1249124211Sdes if (path == NULL || *path == '\0') { 1250126277Sdes child_set_env(&env, &envsize, "PATH", 1251124211Sdes s->pw->pw_uid == 0 ? 1252124211Sdes SUPERUSER_PATH : _PATH_STDPATH); 1253124211Sdes } 125498941Sdes# endif /* HAVE_CYGWIN */ 125598941Sdes#endif /* HAVE_LOGIN_CAP */ 125660573Skris 125760573Skris /* Normal systems set SHELL by default. */ 125860573Skris child_set_env(&env, &envsize, "SHELL", shell); 125960573Skris } 126060573Skris 126160573Skris /* Set custom environment options from RSA authentication. */ 126287255Snectar if (!options.use_login) { 126392559Sdes while (custom_environment) { 126492559Sdes struct envstring *ce = custom_environment; 1265106130Sdes char *str = ce->s; 126692559Sdes 1267106130Sdes for (i = 0; str[i] != '=' && str[i]; i++) 126892559Sdes ; 1269106130Sdes if (str[i] == '=') { 1270106130Sdes str[i] = 0; 1271106130Sdes child_set_env(&env, &envsize, str, str + i + 1); 127292559Sdes } 127392559Sdes custom_environment = ce->next; 1274255767Sdes free(ce->s); 1275255767Sdes free(ce); 127660573Skris } 127760573Skris } 127860573Skris 1279106130Sdes /* SSH_CLIENT deprecated */ 128060573Skris snprintf(buf, sizeof buf, "%.50s %d %d", 1281323124Sdes ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), 1282323124Sdes ssh_local_port(ssh)); 128360573Skris child_set_env(&env, &envsize, "SSH_CLIENT", buf); 128460573Skris 1285113911Sdes laddr = get_local_ipaddr(packet_get_connection_in()); 1286106130Sdes snprintf(buf, sizeof buf, "%.50s %d %.50s %d", 1287323124Sdes ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), 1288323124Sdes laddr, ssh_local_port(ssh)); 1289255767Sdes free(laddr); 1290106130Sdes child_set_env(&env, &envsize, "SSH_CONNECTION", buf); 1291106130Sdes 129276262Sgreen if (s->ttyfd != -1) 129376262Sgreen child_set_env(&env, &envsize, "SSH_TTY", s->tty); 129476262Sgreen if (s->term) 129576262Sgreen child_set_env(&env, &envsize, "TERM", s->term); 129676262Sgreen if (s->display) 129776262Sgreen child_set_env(&env, &envsize, "DISPLAY", s->display); 129865674Skris if (original_command) 129965674Skris child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND", 130065674Skris original_command); 130198941Sdes 1302106130Sdes#ifdef _UNICOS 1303106130Sdes if (cray_tmpdir[0] != '\0') 1304106130Sdes child_set_env(&env, &envsize, "TMPDIR", cray_tmpdir); 1305106130Sdes#endif /* _UNICOS */ 1306106130Sdes 1307147005Sdes /* 1308147005Sdes * Since we clear KRB5CCNAME at startup, if it's set now then it 1309147005Sdes * must have been set by a native authentication method (eg AIX or 1310147005Sdes * SIA), so copy it to the child. 1311147005Sdes */ 1312147005Sdes { 1313147005Sdes char *cp; 1314147005Sdes 1315147005Sdes if ((cp = getenv("KRB5CCNAME")) != NULL) 1316147005Sdes child_set_env(&env, &envsize, "KRB5CCNAME", cp); 1317147005Sdes } 1318147005Sdes 131998941Sdes#ifdef _AIX 132098941Sdes { 132198941Sdes char *cp; 132298941Sdes 132398941Sdes if ((cp = getenv("AUTHSTATE")) != NULL) 132498941Sdes child_set_env(&env, &envsize, "AUTHSTATE", cp); 132598941Sdes read_environment_file(&env, &envsize, "/etc/environment"); 132698941Sdes } 132798941Sdes#endif 132860576Skris#ifdef KRB5 1329128460Sdes if (s->authctxt->krb5_ccname) 133092559Sdes child_set_env(&env, &envsize, "KRB5CCNAME", 1331128460Sdes s->authctxt->krb5_ccname); 133292559Sdes#endif 133369591Sgreen#ifdef USE_PAM 1334106130Sdes /* 1335106130Sdes * Pull in any environment variables that may have 1336106130Sdes * been set by PAM. 1337106130Sdes */ 1338323124Sdes if (options.use_pam && !options.use_login) { 1339126277Sdes char **p; 1340106130Sdes 1341126277Sdes p = fetch_pam_child_environment(); 1342106130Sdes copy_environment(p, &env, &envsize); 1343106130Sdes free_pam_environment(p); 1344126277Sdes 1345126277Sdes p = fetch_pam_environment(); 1346126277Sdes copy_environment(p, &env, &envsize); 1347126277Sdes free_pam_environment(p); 1348106130Sdes } 134969591Sgreen#endif /* USE_PAM */ 135069591Sgreen 135198684Sdes if (auth_sock_name != NULL) 135260573Skris child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, 135398684Sdes auth_sock_name); 135460573Skris 135560573Skris /* read $HOME/.ssh/environment. */ 1356106130Sdes if (options.permit_user_env && !options.use_login) { 135761203Skris snprintf(buf, sizeof buf, "%.200s/.ssh/environment", 1358106130Sdes strcmp(pw->pw_dir, "/") ? pw->pw_dir : ""); 135960573Skris read_environment_file(&env, &envsize, buf); 136060573Skris } 136160573Skris if (debug_flag) { 136260573Skris /* dump the environment */ 136360573Skris fprintf(stderr, "Environment:\n"); 136460573Skris for (i = 0; env[i]; i++) 136560573Skris fprintf(stderr, " %.200s\n", env[i]); 136660573Skris } 136792559Sdes return env; 136892559Sdes} 136992559Sdes 137092559Sdes/* 137192559Sdes * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found 137292559Sdes * first in this order). 137392559Sdes */ 137492559Sdesstatic void 137592559Sdesdo_rc_files(Session *s, const char *shell) 137692559Sdes{ 137792559Sdes FILE *f = NULL; 137892559Sdes char cmd[1024]; 137992559Sdes int do_xauth; 138092559Sdes struct stat st; 138192559Sdes 138292559Sdes do_xauth = 138392559Sdes s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL; 138492559Sdes 1385181111Sdes /* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */ 1386181111Sdes if (!s->is_subsystem && options.adm_forced_command == NULL && 1387295367Sdes !no_user_rc && options.permit_user_rc && 1388295367Sdes stat(_PATH_SSH_USER_RC, &st) >= 0) { 138992559Sdes snprintf(cmd, sizeof cmd, "%s -c '%s %s'", 139092559Sdes shell, _PATH_BSHELL, _PATH_SSH_USER_RC); 139192559Sdes if (debug_flag) 139292559Sdes fprintf(stderr, "Running %s\n", cmd); 139392559Sdes f = popen(cmd, "w"); 139492559Sdes if (f) { 139592559Sdes if (do_xauth) 139692559Sdes fprintf(f, "%s %s\n", s->auth_proto, 139792559Sdes s->auth_data); 139892559Sdes pclose(f); 139992559Sdes } else 140092559Sdes fprintf(stderr, "Could not run %s\n", 140192559Sdes _PATH_SSH_USER_RC); 140292559Sdes } else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) { 140392559Sdes if (debug_flag) 140492559Sdes fprintf(stderr, "Running %s %s\n", _PATH_BSHELL, 140592559Sdes _PATH_SSH_SYSTEM_RC); 140692559Sdes f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w"); 140792559Sdes if (f) { 140892559Sdes if (do_xauth) 140992559Sdes fprintf(f, "%s %s\n", s->auth_proto, 141092559Sdes s->auth_data); 141192559Sdes pclose(f); 141292559Sdes } else 141392559Sdes fprintf(stderr, "Could not run %s\n", 141492559Sdes _PATH_SSH_SYSTEM_RC); 141592559Sdes } else if (do_xauth && options.xauth_location != NULL) { 141692559Sdes /* Add authority data to .Xauthority if appropriate. */ 141792559Sdes if (debug_flag) { 141892559Sdes fprintf(stderr, 1419113911Sdes "Running %.500s remove %.100s\n", 1420126277Sdes options.xauth_location, s->auth_display); 1421113911Sdes fprintf(stderr, 1422113911Sdes "%.500s add %.100s %.100s %.100s\n", 142392559Sdes options.xauth_location, s->auth_display, 142492559Sdes s->auth_proto, s->auth_data); 142592559Sdes } 142692559Sdes snprintf(cmd, sizeof cmd, "%s -q -", 142792559Sdes options.xauth_location); 142892559Sdes f = popen(cmd, "w"); 142992559Sdes if (f) { 1430113911Sdes fprintf(f, "remove %s\n", 1431113911Sdes s->auth_display); 143292559Sdes fprintf(f, "add %s %s %s\n", 143392559Sdes s->auth_display, s->auth_proto, 143492559Sdes s->auth_data); 143592559Sdes pclose(f); 143692559Sdes } else { 143792559Sdes fprintf(stderr, "Could not run %s\n", 143892559Sdes cmd); 143992559Sdes } 144092559Sdes } 144192559Sdes} 144292559Sdes 144392559Sdesstatic void 144492559Sdesdo_nologin(struct passwd *pw) 144592559Sdes{ 144692559Sdes FILE *f = NULL; 1447204917Sdes char buf[1024], *nl, *def_nl = _PATH_NOLOGIN; 1448204917Sdes struct stat sb; 144992559Sdes 145092559Sdes#ifdef HAVE_LOGIN_CAP 1451240075Sdes if (login_getcapbool(lc, "ignorenologin", 0) || pw->pw_uid == 0) 1452204917Sdes return; 1453204917Sdes nl = login_getcapstr(lc, "nologin", def_nl, def_nl); 145492559Sdes#else 1455204917Sdes if (pw->pw_uid == 0) 1456204917Sdes return; 1457204917Sdes nl = def_nl; 145892559Sdes#endif 1459204917Sdes if (stat(nl, &sb) == -1) { 1460204917Sdes if (nl != def_nl) 1461255767Sdes free(nl); 1462204917Sdes return; 146392559Sdes } 1464204917Sdes 1465204917Sdes /* /etc/nologin exists. Print its contents if we can and exit. */ 1466204917Sdes logit("User %.100s not allowed because %s exists", pw->pw_name, nl); 1467204917Sdes if ((f = fopen(nl, "r")) != NULL) { 1468204917Sdes while (fgets(buf, sizeof(buf), f)) 1469204917Sdes fputs(buf, stderr); 1470204917Sdes fclose(f); 1471204917Sdes } 1472204917Sdes exit(254); 147392559Sdes} 147492559Sdes 1475181111Sdes/* 1476181111Sdes * Chroot into a directory after checking it for safety: all path components 1477181111Sdes * must be root-owned directories with strict permissions. 1478181111Sdes */ 1479181111Sdesstatic void 1480181111Sdessafely_chroot(const char *path, uid_t uid) 1481181111Sdes{ 1482181111Sdes const char *cp; 1483295367Sdes char component[PATH_MAX]; 1484181111Sdes struct stat st; 1485181111Sdes 1486181111Sdes if (*path != '/') 1487181111Sdes fatal("chroot path does not begin at root"); 1488181111Sdes if (strlen(path) >= sizeof(component)) 1489181111Sdes fatal("chroot path too long"); 1490181111Sdes 1491181111Sdes /* 1492181111Sdes * Descend the path, checking that each component is a 1493181111Sdes * root-owned directory with strict permissions. 1494181111Sdes */ 1495181111Sdes for (cp = path; cp != NULL;) { 1496181111Sdes if ((cp = strchr(cp, '/')) == NULL) 1497181111Sdes strlcpy(component, path, sizeof(component)); 1498181111Sdes else { 1499181111Sdes cp++; 1500181111Sdes memcpy(component, path, cp - path); 1501181111Sdes component[cp - path] = '\0'; 1502181111Sdes } 1503181111Sdes 1504181111Sdes debug3("%s: checking '%s'", __func__, component); 1505181111Sdes 1506181111Sdes if (stat(component, &st) != 0) 1507181111Sdes fatal("%s: stat(\"%s\"): %s", __func__, 1508181111Sdes component, strerror(errno)); 1509181111Sdes if (st.st_uid != 0 || (st.st_mode & 022) != 0) 1510181111Sdes fatal("bad ownership or modes for chroot " 1511181111Sdes "directory %s\"%s\"", 1512181111Sdes cp == NULL ? "" : "component ", component); 1513181111Sdes if (!S_ISDIR(st.st_mode)) 1514181111Sdes fatal("chroot path %s\"%s\" is not a directory", 1515181111Sdes cp == NULL ? "" : "component ", component); 1516181111Sdes 1517181111Sdes } 1518181111Sdes 1519181111Sdes if (chdir(path) == -1) 1520181111Sdes fatal("Unable to chdir to chroot path \"%s\": " 1521181111Sdes "%s", path, strerror(errno)); 1522181111Sdes if (chroot(path) == -1) 1523181111Sdes fatal("chroot(\"%s\"): %s", path, strerror(errno)); 1524181111Sdes if (chdir("/") == -1) 1525181111Sdes fatal("%s: chdir(/) after chroot: %s", 1526181111Sdes __func__, strerror(errno)); 1527181111Sdes verbose("Changed root directory to \"%s\"", path); 1528181111Sdes} 1529181111Sdes 153092559Sdes/* Set login name, uid, gid, and groups. */ 153198941Sdesvoid 153298684Sdesdo_setusercontext(struct passwd *pw) 153392559Sdes{ 1534181111Sdes char *chroot_path, *tmp; 1535181111Sdes 1536221420Sdes platform_setusercontext(pw); 1537181111Sdes 1538221420Sdes if (platform_privileged_uidswap()) { 153995105Sache#ifdef HAVE_LOGIN_CAP 154098941Sdes if (setusercontext(lc, pw, pw->pw_uid, 1541181111Sdes (LOGIN_SETALL & ~(LOGIN_SETENV|LOGIN_SETPATH|LOGIN_SETUSER))) < 0) { 154298941Sdes perror("unable to set user context"); 154398941Sdes exit(1); 154498941Sdes } 154598941Sdes#else 154692559Sdes if (setlogin(pw->pw_name) < 0) 154792559Sdes error("setlogin failed: %s", strerror(errno)); 154892559Sdes if (setgid(pw->pw_gid) < 0) { 154992559Sdes perror("setgid"); 155092559Sdes exit(1); 155192559Sdes } 155292559Sdes /* Initialize the group list. */ 155392559Sdes if (initgroups(pw->pw_name, pw->pw_gid) < 0) { 155492559Sdes perror("initgroups"); 155592559Sdes exit(1); 155692559Sdes } 155792559Sdes endgrent(); 1558181111Sdes#endif 1559181111Sdes 1560221420Sdes platform_setusercontext_post_groups(pw); 1561204917Sdes 1562296781Sdes if (!in_chroot && options.chroot_directory != NULL && 1563181111Sdes strcasecmp(options.chroot_directory, "none") != 0) { 1564181111Sdes tmp = tilde_expand_filename(options.chroot_directory, 1565181111Sdes pw->pw_uid); 1566181111Sdes chroot_path = percent_expand(tmp, "h", pw->pw_dir, 1567181111Sdes "u", pw->pw_name, (char *)NULL); 1568181111Sdes safely_chroot(chroot_path, pw->pw_uid); 1569181111Sdes free(tmp); 1570181111Sdes free(chroot_path); 1571255767Sdes /* Make sure we don't attempt to chroot again */ 1572255767Sdes free(options.chroot_directory); 1573255767Sdes options.chroot_directory = NULL; 1574296781Sdes in_chroot = 1; 1575181111Sdes } 1576181111Sdes 1577181111Sdes#ifdef HAVE_LOGIN_CAP 1578181111Sdes if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUSER) < 0) { 1579181111Sdes perror("unable to set user context (setuser)"); 1580181111Sdes exit(1); 1581181111Sdes } 1582248619Sdes /* 1583248231Sdes * FreeBSD's setusercontext() will not apply the user's 1584248231Sdes * own umask setting unless running with the user's UID. 1585248231Sdes */ 1586248619Sdes (void) setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUMASK); 1587181111Sdes#else 1588262566Sdes# ifdef USE_LIBIAF 1589296781Sdes /* 1590296781Sdes * In a chroot environment, the set_id() will always fail; 1591296781Sdes * typically because of the lack of necessary authentication 1592296781Sdes * services and runtime such as ./usr/lib/libiaf.so, 1593296781Sdes * ./usr/lib/libpam.so.1, and ./etc/passwd We skip it in the 1594296781Sdes * internal sftp chroot case. We'll lose auditing and ACLs but 1595296781Sdes * permanently_set_uid will take care of the rest. 1596296781Sdes */ 1597296781Sdes if (!in_chroot && set_id(pw->pw_name) != 0) 1598296781Sdes fatal("set_id(%s) Failed", pw->pw_name); 1599262566Sdes# endif /* USE_LIBIAF */ 160092559Sdes /* Permanently switch to the desired uid. */ 160192559Sdes permanently_set_uid(pw); 160298941Sdes#endif 1603255767Sdes } else if (options.chroot_directory != NULL && 1604255767Sdes strcasecmp(options.chroot_directory, "none") != 0) { 1605255767Sdes fatal("server lacks privileges to chroot to ChrootDirectory"); 160692559Sdes } 1607113911Sdes 160892559Sdes if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) 160992559Sdes fatal("Failed to set uids to %u.", (u_int) pw->pw_uid); 161092559Sdes} 161192559Sdes 161298684Sdesstatic void 1613126277Sdesdo_pwchange(Session *s) 1614126277Sdes{ 1615137019Sdes fflush(NULL); 1616126277Sdes fprintf(stderr, "WARNING: Your password has expired.\n"); 1617126277Sdes if (s->ttyfd != -1) { 1618137019Sdes fprintf(stderr, 1619126277Sdes "You must change your password now and login again!\n"); 1620226046Sdes#ifdef WITH_SELINUX 1621226046Sdes setexeccon(NULL); 1622226046Sdes#endif 1623147005Sdes#ifdef PASSWD_NEEDS_USERNAME 1624147005Sdes execl(_PATH_PASSWD_PROG, "passwd", s->pw->pw_name, 1625147005Sdes (char *)NULL); 1626147005Sdes#else 1627126277Sdes execl(_PATH_PASSWD_PROG, "passwd", (char *)NULL); 1628147005Sdes#endif 1629126277Sdes perror("passwd"); 1630126277Sdes } else { 1631126277Sdes fprintf(stderr, 1632126277Sdes "Password change required but no TTY available.\n"); 1633126277Sdes } 1634126277Sdes exit(1); 1635126277Sdes} 1636126277Sdes 1637126277Sdesstatic void 163898684Sdeslaunch_login(struct passwd *pw, const char *hostname) 163998684Sdes{ 164098684Sdes /* Launch login(1). */ 164198684Sdes 164298941Sdes execl(LOGIN_PROGRAM, "login", "-h", hostname, 164398941Sdes#ifdef xxxLOGIN_NEEDS_TERM 164498941Sdes (s->term ? s->term : "unknown"), 164598941Sdes#endif /* LOGIN_NEEDS_TERM */ 164698941Sdes#ifdef LOGIN_NO_ENDOPT 164798941Sdes "-p", "-f", pw->pw_name, (char *)NULL); 164898941Sdes#else 164998684Sdes "-p", "-f", "--", pw->pw_name, (char *)NULL); 165098941Sdes#endif 165198684Sdes 165298684Sdes /* Login couldn't be executed, die. */ 165398684Sdes 165498684Sdes perror("login"); 165598684Sdes exit(1); 165698684Sdes} 165798684Sdes 1658126277Sdesstatic void 1659126277Sdeschild_close_fds(void) 1660126277Sdes{ 1661295367Sdes extern int auth_sock; 1662255767Sdes 1663295367Sdes if (auth_sock != -1) { 1664295367Sdes close(auth_sock); 1665295367Sdes auth_sock = -1; 1666255767Sdes } 1667255767Sdes 1668126277Sdes if (packet_get_connection_in() == packet_get_connection_out()) 1669126277Sdes close(packet_get_connection_in()); 1670126277Sdes else { 1671126277Sdes close(packet_get_connection_in()); 1672126277Sdes close(packet_get_connection_out()); 1673126277Sdes } 1674126277Sdes /* 1675126277Sdes * Close all descriptors related to channels. They will still remain 1676126277Sdes * open in the parent. 1677126277Sdes */ 1678126277Sdes /* XXX better use close-on-exec? -markus */ 1679126277Sdes channel_close_all(); 1680126277Sdes 1681126277Sdes /* 1682126277Sdes * Close any extra file descriptors. Note that there may still be 1683126277Sdes * descriptors left by system functions. They will be closed later. 1684126277Sdes */ 1685126277Sdes endpwent(); 1686126277Sdes 1687126277Sdes /* 1688157019Sdes * Close any extra open file descriptors so that we don't have them 1689126277Sdes * hanging around in clients. Note that we want to do this after 1690126277Sdes * initgroups, because at least on Solaris 2.3 it leaves file 1691126277Sdes * descriptors open. 1692126277Sdes */ 1693221420Sdes closefrom(STDERR_FILENO + 1); 1694126277Sdes} 1695126277Sdes 169692559Sdes/* 169792559Sdes * Performs common processing for the child, such as setting up the 169892559Sdes * environment, closing extra file descriptors, setting the user and group 169992559Sdes * ids, and executing the command or shell. 170092559Sdes */ 1701181111Sdes#define ARGV_MAX 10 170292559Sdesvoid 170392559Sdesdo_child(Session *s, const char *command) 170492559Sdes{ 1705323124Sdes struct ssh *ssh = active_state; /* XXX */ 170692559Sdes extern char **environ; 170798941Sdes char **env; 1708181111Sdes char *argv[ARGV_MAX]; 170992559Sdes const char *shell, *shell0, *hostname = NULL; 171092559Sdes struct passwd *pw = s->pw; 1711181111Sdes int r = 0; 171292559Sdes 171392559Sdes /* remove hostkey from the child's memory */ 171492559Sdes destroy_sensitive_data(); 171592559Sdes 1716126277Sdes /* Force a password change */ 1717126277Sdes if (s->authctxt->force_pwchange) { 1718126277Sdes do_setusercontext(pw); 1719126277Sdes child_close_fds(); 1720126277Sdes do_pwchange(s); 1721126277Sdes exit(1); 1722126277Sdes } 1723126277Sdes 172492559Sdes /* login(1) is only called if we execute the login shell */ 172592559Sdes if (options.use_login && command != NULL) 172692559Sdes options.use_login = 0; 172792559Sdes 1728106130Sdes#ifdef _UNICOS 1729106130Sdes cray_setup(pw->pw_uid, pw->pw_name, command); 1730106130Sdes#endif /* _UNICOS */ 1731106130Sdes 173292559Sdes /* 173392559Sdes * Login(1) does this as well, and it needs uid 0 for the "-h" 173492559Sdes * switch, so we let login(1) to this for us. 173592559Sdes */ 173692559Sdes if (!options.use_login) { 173798941Sdes#ifdef HAVE_OSF_SIA 1738113911Sdes session_setup_sia(pw, s->ttyfd == -1 ? NULL : s->tty); 173998941Sdes if (!check_quietlogin(s, command)) 174098941Sdes do_motd(); 174198941Sdes#else /* HAVE_OSF_SIA */ 1742157019Sdes /* When PAM is enabled we rely on it to do the nologin check */ 1743157019Sdes if (!options.use_pam) 1744157019Sdes do_nologin(pw); 174598941Sdes do_setusercontext(pw); 1746137019Sdes /* 1747137019Sdes * PAM session modules in do_setusercontext may have 1748137019Sdes * generated messages, so if this in an interactive 1749137019Sdes * login then display them too. 1750137019Sdes */ 1751147005Sdes if (!check_quietlogin(s, command)) 1752137019Sdes display_loginmsg(); 175398941Sdes#endif /* HAVE_OSF_SIA */ 175492559Sdes } 175592559Sdes 1756147005Sdes#ifdef USE_PAM 1757147005Sdes if (options.use_pam && !options.use_login && !is_pam_session_open()) { 1758147005Sdes debug3("PAM session not opened, exiting"); 1759147005Sdes display_loginmsg(); 1760147005Sdes exit(254); 1761147005Sdes } 1762147005Sdes#endif 1763147005Sdes 176492559Sdes /* 176592559Sdes * Get the shell from the password data. An empty shell field is 176692559Sdes * legal, and means /bin/sh. 176792559Sdes */ 176892559Sdes shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; 1769113911Sdes 1770113911Sdes /* 1771113911Sdes * Make sure $SHELL points to the shell from the password file, 1772113911Sdes * even if shell is overridden from login.conf 1773113911Sdes */ 1774113911Sdes env = do_setup_env(s, shell); 1775113911Sdes 177692559Sdes#ifdef HAVE_LOGIN_CAP 177792559Sdes shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell); 177892559Sdes#endif 177992559Sdes 178065674Skris /* we have to stash the hostname before we close our socket. */ 178165674Skris if (options.use_login) 1782323124Sdes hostname = session_get_remote_name_or_ip(ssh, utmp_len, 1783124211Sdes options.use_dns); 178460573Skris /* 178560573Skris * Close the connection descriptors; note that this is the child, and 178660573Skris * the server will still have the socket open, and it is important 178760573Skris * that we do not shutdown it. Note that the descriptors cannot be 178860573Skris * closed before building the environment, as we call 1789323124Sdes * ssh_remote_ipaddr there. 179060573Skris */ 1791126277Sdes child_close_fds(); 1792126277Sdes 179360573Skris /* 1794126277Sdes * Must take new environment into use so that .ssh/rc, 1795126277Sdes * /etc/ssh/sshrc and xauth are run in the proper environment. 179660573Skris */ 1797126277Sdes environ = env; 179860573Skris 1799126277Sdes#if defined(KRB5) && defined(USE_AFS) 180060573Skris /* 1801126277Sdes * At this point, we check to see if AFS is active and if we have 1802126277Sdes * a valid Kerberos 5 TGT. If so, it seems like a good idea to see 1803126277Sdes * if we can (and need to) extend the ticket into an AFS token. If 1804126277Sdes * we don't do this, we run into potential problems if the user's 1805126277Sdes * home directory is in AFS and it's not world-readable. 180660573Skris */ 180760573Skris 1808126277Sdes if (options.kerberos_get_afs_token && k_hasafs() && 1809149753Sdes (s->authctxt->krb5_ctx != NULL)) { 1810126277Sdes char cell[64]; 181176262Sgreen 1812126277Sdes debug("Getting AFS token"); 181360573Skris 1814126277Sdes k_setpag(); 1815126277Sdes 1816126277Sdes if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0) 1817126277Sdes krb5_afslog(s->authctxt->krb5_ctx, 1818126277Sdes s->authctxt->krb5_fwd_ccache, cell, NULL); 1819126277Sdes 1820126277Sdes krb5_afslog_home(s->authctxt->krb5_ctx, 1821126277Sdes s->authctxt->krb5_fwd_ccache, NULL, NULL, pw->pw_dir); 1822126277Sdes } 1823126277Sdes#endif 1824126277Sdes 1825157019Sdes /* Change current directory to the user's home directory. */ 182692559Sdes if (chdir(pw->pw_dir) < 0) { 1827181111Sdes /* Suppress missing homedir warning for chroot case */ 182892559Sdes#ifdef HAVE_LOGIN_CAP 1829181111Sdes r = login_getcapbool(lc, "requirehome", 0); 1830181111Sdes#endif 1831296781Sdes if (r || !in_chroot) { 1832181111Sdes fprintf(stderr, "Could not chdir to home " 1833181111Sdes "directory %s: %s\n", pw->pw_dir, 1834181111Sdes strerror(errno)); 1835296781Sdes } 1836181111Sdes if (r) 183792559Sdes exit(1); 183892559Sdes } 183992559Sdes 1840181111Sdes closefrom(STDERR_FILENO + 1); 1841181111Sdes 184292559Sdes if (!options.use_login) 184392559Sdes do_rc_files(s, shell); 184492559Sdes 184576262Sgreen /* restore SIGPIPE for child */ 1846162856Sdes signal(SIGPIPE, SIG_DFL); 184776262Sgreen 1848204917Sdes if (s->is_subsystem == SUBSYSTEM_INT_SFTP_ERROR) { 1849204917Sdes printf("This service allows sftp connections only.\n"); 1850204917Sdes fflush(NULL); 1851204917Sdes exit(1); 1852204917Sdes } else if (s->is_subsystem == SUBSYSTEM_INT_SFTP) { 1853181111Sdes extern int optind, optreset; 1854181111Sdes int i; 1855181111Sdes char *p, *args; 1856181111Sdes 1857197679Sdes setproctitle("%s@%s", s->pw->pw_name, INTERNAL_SFTP_NAME); 1858192595Sdes args = xstrdup(command ? command : "sftp-server"); 1859181111Sdes for (i = 0, (p = strtok(args, " ")); p; (p = strtok(NULL, " "))) 1860181111Sdes if (i < ARGV_MAX - 1) 1861181111Sdes argv[i++] = p; 1862181111Sdes argv[i] = NULL; 1863181111Sdes optind = optreset = 1; 1864181111Sdes __progname = argv[0]; 1865204917Sdes#ifdef WITH_SELINUX 1866204917Sdes ssh_selinux_change_context("sftpd_t"); 1867204917Sdes#endif 1868181111Sdes exit(sftp_server_main(i, argv, s->pw)); 1869181111Sdes } 1870181111Sdes 1871204917Sdes fflush(NULL); 1872204917Sdes 187392559Sdes if (options.use_login) { 187498684Sdes launch_login(pw, hostname); 187598684Sdes /* NEVERREACHED */ 187692559Sdes } 187792559Sdes 187892559Sdes /* Get the last component of the shell name. */ 187992559Sdes if ((shell0 = strrchr(shell, '/')) != NULL) 188092559Sdes shell0++; 188192559Sdes else 188292559Sdes shell0 = shell; 188392559Sdes 188460573Skris /* 188560573Skris * If we have no command, execute the shell. In this case, the shell 188660573Skris * name to be passed in argv[0] is preceded by '-' to indicate that 188760573Skris * this is a login shell. 188860573Skris */ 188960573Skris if (!command) { 189092559Sdes char argv0[256]; 189160573Skris 189292559Sdes /* Start the shell. Set initial character to '-'. */ 189392559Sdes argv0[0] = '-'; 189476262Sgreen 189592559Sdes if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1) 189692559Sdes >= sizeof(argv0) - 1) { 189792559Sdes errno = EINVAL; 189860573Skris perror(shell); 189960573Skris exit(1); 190092559Sdes } 190160573Skris 190292559Sdes /* Execute the shell. */ 190392559Sdes argv[0] = argv0; 190492559Sdes argv[1] = NULL; 190592559Sdes execve(shell, argv, env); 190660573Skris 190792559Sdes /* Executing the shell failed. */ 190892559Sdes perror(shell); 190992559Sdes exit(1); 191060573Skris } 191160573Skris /* 191260573Skris * Execute the command using the user's shell. This uses the -c 191360573Skris * option to execute the command. 191460573Skris */ 191592559Sdes argv[0] = (char *) shell0; 191660573Skris argv[1] = "-c"; 191760573Skris argv[2] = (char *) command; 191860573Skris argv[3] = NULL; 191960573Skris execve(shell, argv, env); 192060573Skris perror(shell); 192160573Skris exit(1); 192260573Skris} 192360573Skris 1924181111Sdesvoid 1925181111Sdessession_unused(int id) 1926181111Sdes{ 1927181111Sdes debug3("%s: session id %d unused", __func__, id); 1928181111Sdes if (id >= options.max_sessions || 1929181111Sdes id >= sessions_nalloc) { 1930181111Sdes fatal("%s: insane session id %d (max %d nalloc %d)", 1931181111Sdes __func__, id, options.max_sessions, sessions_nalloc); 1932181111Sdes } 1933264377Sdes memset(&sessions[id], 0, sizeof(*sessions)); 1934181111Sdes sessions[id].self = id; 1935181111Sdes sessions[id].used = 0; 1936181111Sdes sessions[id].chanid = -1; 1937181111Sdes sessions[id].ptyfd = -1; 1938181111Sdes sessions[id].ttyfd = -1; 1939181111Sdes sessions[id].ptymaster = -1; 1940181111Sdes sessions[id].x11_chanids = NULL; 1941181111Sdes sessions[id].next_unused = sessions_first_unused; 1942181111Sdes sessions_first_unused = id; 1943181111Sdes} 1944181111Sdes 194560573SkrisSession * 194660573Skrissession_new(void) 194760573Skris{ 1948181111Sdes Session *s, *tmp; 1949181111Sdes 1950181111Sdes if (sessions_first_unused == -1) { 1951181111Sdes if (sessions_nalloc >= options.max_sessions) 1952181111Sdes return NULL; 1953181111Sdes debug2("%s: allocate (allocated %d max %d)", 1954181111Sdes __func__, sessions_nalloc, options.max_sessions); 1955295367Sdes tmp = xreallocarray(sessions, sessions_nalloc + 1, 1956181111Sdes sizeof(*sessions)); 1957181111Sdes if (tmp == NULL) { 1958181111Sdes error("%s: cannot allocate %d sessions", 1959181111Sdes __func__, sessions_nalloc + 1); 1960181111Sdes return NULL; 196160573Skris } 1962181111Sdes sessions = tmp; 1963181111Sdes session_unused(sessions_nalloc++); 196460573Skris } 1965181111Sdes 1966181111Sdes if (sessions_first_unused >= sessions_nalloc || 1967181111Sdes sessions_first_unused < 0) { 1968181111Sdes fatal("%s: insane first_unused %d max %d nalloc %d", 1969181111Sdes __func__, sessions_first_unused, options.max_sessions, 1970181111Sdes sessions_nalloc); 197160573Skris } 1972181111Sdes 1973181111Sdes s = &sessions[sessions_first_unused]; 1974181111Sdes if (s->used) { 1975181111Sdes fatal("%s: session %d already used", 1976181111Sdes __func__, sessions_first_unused); 1977181111Sdes } 1978181111Sdes sessions_first_unused = s->next_unused; 1979181111Sdes s->used = 1; 1980181111Sdes s->next_unused = -1; 1981181111Sdes debug("session_new: session %d", s->self); 1982181111Sdes 1983181111Sdes return s; 198460573Skris} 198560573Skris 198692559Sdesstatic void 198760573Skrissession_dump(void) 198860573Skris{ 198960573Skris int i; 1990181111Sdes for (i = 0; i < sessions_nalloc; i++) { 199160573Skris Session *s = &sessions[i]; 1992181111Sdes 1993181111Sdes debug("dump: used %d next_unused %d session %d %p " 1994181111Sdes "channel %d pid %ld", 199560573Skris s->used, 1996181111Sdes s->next_unused, 199760573Skris s->self, 199860573Skris s, 199960573Skris s->chanid, 200098684Sdes (long)s->pid); 200160573Skris } 200260573Skris} 200360573Skris 200460573Skrisint 200592559Sdessession_open(Authctxt *authctxt, int chanid) 200660573Skris{ 200760573Skris Session *s = session_new(); 200860573Skris debug("session_open: channel %d", chanid); 200960573Skris if (s == NULL) { 201060573Skris error("no more sessions"); 201160573Skris return 0; 201260573Skris } 201392559Sdes s->authctxt = authctxt; 201492559Sdes s->pw = authctxt->pw; 2015126277Sdes if (s->pw == NULL || !authctxt->valid) 201676262Sgreen fatal("no user for session %d", s->self); 201760573Skris debug("session_open: session %d: link with channel %d", s->self, chanid); 201860573Skris s->chanid = chanid; 201960573Skris return 1; 202060573Skris} 202160573Skris 202298684SdesSession * 202398684Sdessession_by_tty(char *tty) 202498684Sdes{ 202598684Sdes int i; 2026181111Sdes for (i = 0; i < sessions_nalloc; i++) { 202798684Sdes Session *s = &sessions[i]; 202898684Sdes if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) { 202998684Sdes debug("session_by_tty: session %d tty %s", i, tty); 203098684Sdes return s; 203198684Sdes } 203298684Sdes } 203398684Sdes debug("session_by_tty: unknown tty %.100s", tty); 203498684Sdes session_dump(); 203598684Sdes return NULL; 203698684Sdes} 203798684Sdes 203892559Sdesstatic Session * 203960573Skrissession_by_channel(int id) 204060573Skris{ 204160573Skris int i; 2042181111Sdes for (i = 0; i < sessions_nalloc; i++) { 204360573Skris Session *s = &sessions[i]; 204460573Skris if (s->used && s->chanid == id) { 2045181111Sdes debug("session_by_channel: session %d channel %d", 2046181111Sdes i, id); 204760573Skris return s; 204860573Skris } 204960573Skris } 205060573Skris debug("session_by_channel: unknown channel %d", id); 205160573Skris session_dump(); 205260573Skris return NULL; 205360573Skris} 205460573Skris 205592559Sdesstatic Session * 2056149753Sdessession_by_x11_channel(int id) 2057149753Sdes{ 2058149753Sdes int i, j; 2059149753Sdes 2060181111Sdes for (i = 0; i < sessions_nalloc; i++) { 2061149753Sdes Session *s = &sessions[i]; 2062149753Sdes 2063149753Sdes if (s->x11_chanids == NULL || !s->used) 2064149753Sdes continue; 2065149753Sdes for (j = 0; s->x11_chanids[j] != -1; j++) { 2066149753Sdes if (s->x11_chanids[j] == id) { 2067149753Sdes debug("session_by_x11_channel: session %d " 2068149753Sdes "channel %d", s->self, id); 2069149753Sdes return s; 2070149753Sdes } 2071149753Sdes } 2072149753Sdes } 2073149753Sdes debug("session_by_x11_channel: unknown channel %d", id); 2074149753Sdes session_dump(); 2075149753Sdes return NULL; 2076149753Sdes} 2077149753Sdes 2078149753Sdesstatic Session * 207960573Skrissession_by_pid(pid_t pid) 208060573Skris{ 208160573Skris int i; 208298684Sdes debug("session_by_pid: pid %ld", (long)pid); 2083181111Sdes for (i = 0; i < sessions_nalloc; i++) { 208460573Skris Session *s = &sessions[i]; 208560573Skris if (s->used && s->pid == pid) 208660573Skris return s; 208760573Skris } 208898684Sdes error("session_by_pid: unknown pid %ld", (long)pid); 208960573Skris session_dump(); 209060573Skris return NULL; 209160573Skris} 209260573Skris 209392559Sdesstatic int 209460573Skrissession_window_change_req(Session *s) 209560573Skris{ 209660573Skris s->col = packet_get_int(); 209760573Skris s->row = packet_get_int(); 209860573Skris s->xpixel = packet_get_int(); 209960573Skris s->ypixel = packet_get_int(); 210092559Sdes packet_check_eom(); 210160573Skris pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); 210260573Skris return 1; 210360573Skris} 210460573Skris 210592559Sdesstatic int 210660573Skrissession_pty_req(Session *s) 210760573Skris{ 210876262Sgreen u_int len; 210976262Sgreen int n_bytes; 211060573Skris 2111262566Sdes if (no_pty_flag || !options.permit_tty) { 211292559Sdes debug("Allocating a pty not permitted for this authentication."); 211365674Skris return 0; 211492559Sdes } 211592559Sdes if (s->ttyfd != -1) { 211692559Sdes packet_disconnect("Protocol error: you already have a pty."); 211760573Skris return 0; 211892559Sdes } 211992559Sdes 212060573Skris s->term = packet_get_string(&len); 212192559Sdes 212292559Sdes if (compat20) { 212392559Sdes s->col = packet_get_int(); 212492559Sdes s->row = packet_get_int(); 212592559Sdes } else { 212692559Sdes s->row = packet_get_int(); 212792559Sdes s->col = packet_get_int(); 212892559Sdes } 212960573Skris s->xpixel = packet_get_int(); 213060573Skris s->ypixel = packet_get_int(); 213160573Skris 213260573Skris if (strcmp(s->term, "") == 0) { 2133255767Sdes free(s->term); 213460573Skris s->term = NULL; 213560573Skris } 213692559Sdes 213760573Skris /* Allocate a pty and open it. */ 213892559Sdes debug("Allocating pty."); 2139181111Sdes if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, 2140181111Sdes sizeof(s->tty)))) { 2141255767Sdes free(s->term); 214260573Skris s->term = NULL; 214360573Skris s->ptyfd = -1; 214460573Skris s->ttyfd = -1; 214560573Skris error("session_pty_req: session %d alloc failed", s->self); 214660573Skris return 0; 214760573Skris } 214860573Skris debug("session_pty_req: session %d alloc %s", s->self, s->tty); 214992559Sdes 215092559Sdes /* for SSH1 the tty modes length is not given */ 215192559Sdes if (!compat20) 215292559Sdes n_bytes = packet_remaining(); 215392559Sdes tty_parse_modes(s->ttyfd, &n_bytes); 215492559Sdes 215598684Sdes if (!use_privsep) 215698684Sdes pty_setowner(s->pw, s->tty); 215792559Sdes 215892559Sdes /* Set window size from the packet. */ 215960573Skris pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); 216060573Skris 216192559Sdes packet_check_eom(); 216260573Skris session_proctitle(s); 216360573Skris return 1; 216460573Skris} 216560573Skris 216692559Sdesstatic int 216760573Skrissession_subsystem_req(Session *s) 216860573Skris{ 216992559Sdes struct stat st; 217076262Sgreen u_int len; 217160573Skris int success = 0; 2172262566Sdes char *prog, *cmd; 2173149753Sdes u_int i; 217460573Skris 2175262566Sdes s->subsys = packet_get_string(&len); 217692559Sdes packet_check_eom(); 2177262566Sdes debug2("subsystem request for %.100s by user %s", s->subsys, 2178215116Sdes s->pw->pw_name); 217960573Skris 218065674Skris for (i = 0; i < options.num_subsystems; i++) { 2181262566Sdes if (strcmp(s->subsys, options.subsystem_name[i]) == 0) { 2182162856Sdes prog = options.subsystem_command[i]; 2183162856Sdes cmd = options.subsystem_args[i]; 2184204917Sdes if (strcmp(INTERNAL_SFTP_NAME, prog) == 0) { 2185181111Sdes s->is_subsystem = SUBSYSTEM_INT_SFTP; 2186204917Sdes debug("subsystem: %s", prog); 2187181111Sdes } else { 2188204917Sdes if (stat(prog, &st) < 0) 2189204917Sdes debug("subsystem: cannot stat %s: %s", 2190204917Sdes prog, strerror(errno)); 2191181111Sdes s->is_subsystem = SUBSYSTEM_EXT; 2192204917Sdes debug("subsystem: exec() %s", cmd); 219392559Sdes } 2194181111Sdes success = do_exec(s, cmd) == 0; 219592559Sdes break; 219665674Skris } 219765674Skris } 219865674Skris 219965674Skris if (!success) 2200262566Sdes logit("subsystem request for %.100s by user %s failed, " 2201262566Sdes "subsystem not found", s->subsys, s->pw->pw_name); 220265674Skris 220360573Skris return success; 220460573Skris} 220560573Skris 220692559Sdesstatic int 220760573Skrissession_x11_req(Session *s) 220860573Skris{ 220992559Sdes int success; 221060573Skris 2211149753Sdes if (s->auth_proto != NULL || s->auth_data != NULL) { 2212149753Sdes error("session_x11_req: session %d: " 2213157019Sdes "x11 forwarding already active", s->self); 2214149753Sdes return 0; 2215149753Sdes } 221660573Skris s->single_connection = packet_get_char(); 221760573Skris s->auth_proto = packet_get_string(NULL); 221860573Skris s->auth_data = packet_get_string(NULL); 221960573Skris s->screen = packet_get_int(); 222092559Sdes packet_check_eom(); 222160573Skris 2222296781Sdes if (xauth_valid_string(s->auth_proto) && 2223296781Sdes xauth_valid_string(s->auth_data)) 2224296781Sdes success = session_setup_x11fwd(s); 2225296781Sdes else { 2226296781Sdes success = 0; 2227296781Sdes error("Invalid X11 forwarding data"); 2228296781Sdes } 222992559Sdes if (!success) { 2230255767Sdes free(s->auth_proto); 2231255767Sdes free(s->auth_data); 223292559Sdes s->auth_proto = NULL; 223392559Sdes s->auth_data = NULL; 223460573Skris } 223592559Sdes return success; 223660573Skris} 223760573Skris 223892559Sdesstatic int 223965674Skrissession_shell_req(Session *s) 224065674Skris{ 224192559Sdes packet_check_eom(); 2242181111Sdes return do_exec(s, NULL) == 0; 224365674Skris} 224465674Skris 224592559Sdesstatic int 224665674Skrissession_exec_req(Session *s) 224765674Skris{ 2248181111Sdes u_int len, success; 2249181111Sdes 225065674Skris char *command = packet_get_string(&len); 225192559Sdes packet_check_eom(); 2252181111Sdes success = do_exec(s, command) == 0; 2253255767Sdes free(command); 2254181111Sdes return success; 225565674Skris} 225665674Skris 225792559Sdesstatic int 2258124211Sdessession_break_req(Session *s) 2259124211Sdes{ 2260124211Sdes 2261137019Sdes packet_get_int(); /* ignored */ 2262124211Sdes packet_check_eom(); 2263124211Sdes 2264240075Sdes if (s->ptymaster == -1 || tcsendbreak(s->ptymaster, 0) < 0) 2265124211Sdes return 0; 2266124211Sdes return 1; 2267124211Sdes} 2268124211Sdes 2269124211Sdesstatic int 2270137019Sdessession_env_req(Session *s) 2271137019Sdes{ 2272137019Sdes char *name, *val; 2273137019Sdes u_int name_len, val_len, i; 2274137019Sdes 2275264377Sdes name = packet_get_cstring(&name_len); 2276264377Sdes val = packet_get_cstring(&val_len); 2277137019Sdes packet_check_eom(); 2278137019Sdes 2279137019Sdes /* Don't set too many environment variables */ 2280137019Sdes if (s->num_env > 128) { 2281137019Sdes debug2("Ignoring env request %s: too many env vars", name); 2282137019Sdes goto fail; 2283137019Sdes } 2284137019Sdes 2285137019Sdes for (i = 0; i < options.num_accept_env; i++) { 2286137019Sdes if (match_pattern(name, options.accept_env[i])) { 2287137019Sdes debug2("Setting env %d: %s=%s", s->num_env, name, val); 2288295367Sdes s->env = xreallocarray(s->env, s->num_env + 1, 2289162856Sdes sizeof(*s->env)); 2290137019Sdes s->env[s->num_env].name = name; 2291137019Sdes s->env[s->num_env].val = val; 2292137019Sdes s->num_env++; 2293137019Sdes return (1); 2294137019Sdes } 2295137019Sdes } 2296137019Sdes debug2("Ignoring env request %s: disallowed name", name); 2297137019Sdes 2298137019Sdes fail: 2299255767Sdes free(name); 2300255767Sdes free(val); 2301137019Sdes return (0); 2302137019Sdes} 2303137019Sdes 2304137019Sdesstatic int 230576262Sgreensession_auth_agent_req(Session *s) 230676262Sgreen{ 230776262Sgreen static int called = 0; 230892559Sdes packet_check_eom(); 2309181111Sdes if (no_agent_forwarding_flag || !options.allow_agent_forwarding) { 231076262Sgreen debug("session_auth_agent_req: no_agent_forwarding_flag"); 231176262Sgreen return 0; 231276262Sgreen } 231376262Sgreen if (called) { 231476262Sgreen return 0; 231576262Sgreen } else { 231676262Sgreen called = 1; 231776262Sgreen return auth_input_request_forwarding(s->pw); 231876262Sgreen } 231976262Sgreen} 232076262Sgreen 232192559Sdesint 232292559Sdessession_input_channel_req(Channel *c, const char *rtype) 232360573Skris{ 232460573Skris int success = 0; 232560573Skris Session *s; 232660573Skris 232792559Sdes if ((s = session_by_channel(c->self)) == NULL) { 2328124211Sdes logit("session_input_channel_req: no session %d req %.100s", 232992559Sdes c->self, rtype); 233092559Sdes return 0; 233192559Sdes } 233292559Sdes debug("session_input_channel_req: session %d req %s", s->self, rtype); 233360573Skris 233460573Skris /* 233576262Sgreen * a session is in LARVAL state until a shell, a command 233676262Sgreen * or a subsystem is executed 233760573Skris */ 233860573Skris if (c->type == SSH_CHANNEL_LARVAL) { 233960573Skris if (strcmp(rtype, "shell") == 0) { 234065674Skris success = session_shell_req(s); 234160573Skris } else if (strcmp(rtype, "exec") == 0) { 234265674Skris success = session_exec_req(s); 234360573Skris } else if (strcmp(rtype, "pty-req") == 0) { 2344181111Sdes success = session_pty_req(s); 234560573Skris } else if (strcmp(rtype, "x11-req") == 0) { 234660573Skris success = session_x11_req(s); 234776262Sgreen } else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) { 234876262Sgreen success = session_auth_agent_req(s); 234960573Skris } else if (strcmp(rtype, "subsystem") == 0) { 235060573Skris success = session_subsystem_req(s); 2351137019Sdes } else if (strcmp(rtype, "env") == 0) { 2352137019Sdes success = session_env_req(s); 235360573Skris } 235460573Skris } 235560573Skris if (strcmp(rtype, "window-change") == 0) { 235660573Skris success = session_window_change_req(s); 2357137019Sdes } else if (strcmp(rtype, "break") == 0) { 2358137019Sdes success = session_break_req(s); 235960573Skris } 2360137019Sdes 236192559Sdes return success; 236260573Skris} 236360573Skris 236460573Skrisvoid 2365215116Sdessession_set_fds(Session *s, int fdin, int fdout, int fderr, int ignore_fderr, 2366215116Sdes int is_tty) 236760573Skris{ 236860573Skris if (!compat20) 236960573Skris fatal("session_set_fds: called for proto != 2.0"); 237060573Skris /* 237160573Skris * now that have a child and a pipe to the child, 237260573Skris * we can activate our channel and register the fd's 237360573Skris */ 237460573Skris if (s->chanid == -1) 237560573Skris fatal("no channel for session %d", s->self); 2376294693Sdes channel_set_fds(s->chanid, 2377294693Sdes fdout, fdin, fderr, 2378294693Sdes ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, 2379294693Sdes 1, is_tty, CHAN_SES_WINDOW_DEFAULT); 238060573Skris} 238160573Skris 238292559Sdes/* 238392559Sdes * Function to perform pty cleanup. Also called if we get aborted abnormally 238492559Sdes * (e.g., due to a dropped connection). 238592559Sdes */ 238698684Sdesvoid 2387126277Sdessession_pty_cleanup2(Session *s) 238860573Skris{ 238992559Sdes if (s == NULL) { 239092559Sdes error("session_pty_cleanup: no session"); 239160573Skris return; 239292559Sdes } 239392559Sdes if (s->ttyfd == -1) 239492559Sdes return; 239560573Skris 239676262Sgreen debug("session_pty_cleanup: session %d release %s", s->self, s->tty); 239760573Skris 239860573Skris /* Record that the user has logged out. */ 239992559Sdes if (s->pid != 0) 240098941Sdes record_logout(s->pid, s->tty, s->pw->pw_name); 240160573Skris 240260573Skris /* Release the pseudo-tty. */ 240398684Sdes if (getuid() == 0) 240498684Sdes pty_release(s->tty); 240560573Skris 240660573Skris /* 240760573Skris * Close the server side of the socket pairs. We must do this after 240860573Skris * the pty cleanup, so that another process doesn't get this pty 240960573Skris * while we're still cleaning up. 241060573Skris */ 2411181111Sdes if (s->ptymaster != -1 && close(s->ptymaster) < 0) 2412181111Sdes error("close(s->ptymaster/%d): %s", 2413181111Sdes s->ptymaster, strerror(errno)); 241492559Sdes 241592559Sdes /* unlink pty from session */ 241692559Sdes s->ttyfd = -1; 241760573Skris} 241860573Skris 241998684Sdesvoid 2420126277Sdessession_pty_cleanup(Session *s) 242198684Sdes{ 2422126277Sdes PRIVSEP(session_pty_cleanup2(s)); 242398684Sdes} 242498684Sdes 2425106130Sdesstatic char * 2426106130Sdessig2name(int sig) 2427106130Sdes{ 2428106130Sdes#define SSH_SIG(x) if (sig == SIG ## x) return #x 2429106130Sdes SSH_SIG(ABRT); 2430106130Sdes SSH_SIG(ALRM); 2431106130Sdes SSH_SIG(FPE); 2432106130Sdes SSH_SIG(HUP); 2433106130Sdes SSH_SIG(ILL); 2434106130Sdes SSH_SIG(INT); 2435106130Sdes SSH_SIG(KILL); 2436106130Sdes SSH_SIG(PIPE); 2437106130Sdes SSH_SIG(QUIT); 2438106130Sdes SSH_SIG(SEGV); 2439106130Sdes SSH_SIG(TERM); 2440106130Sdes SSH_SIG(USR1); 2441106130Sdes SSH_SIG(USR2); 2442106130Sdes#undef SSH_SIG 2443106130Sdes return "SIG@openssh.com"; 2444106130Sdes} 2445106130Sdes 244692559Sdesstatic void 2447149753Sdessession_close_x11(int id) 2448149753Sdes{ 2449149753Sdes Channel *c; 2450149753Sdes 2451157019Sdes if ((c = channel_by_id(id)) == NULL) { 2452149753Sdes debug("session_close_x11: x11 channel %d missing", id); 2453149753Sdes } else { 2454149753Sdes /* Detach X11 listener */ 2455149753Sdes debug("session_close_x11: detach x11 channel %d", id); 2456149753Sdes channel_cancel_cleanup(id); 2457149753Sdes if (c->ostate != CHAN_OUTPUT_CLOSED) 2458149753Sdes chan_mark_dead(c); 2459149753Sdes } 2460149753Sdes} 2461149753Sdes 2462149753Sdesstatic void 2463149753Sdessession_close_single_x11(int id, void *arg) 2464149753Sdes{ 2465149753Sdes Session *s; 2466149753Sdes u_int i; 2467149753Sdes 2468149753Sdes debug3("session_close_single_x11: channel %d", id); 2469149753Sdes channel_cancel_cleanup(id); 2470181111Sdes if ((s = session_by_x11_channel(id)) == NULL) 2471149753Sdes fatal("session_close_single_x11: no x11 channel %d", id); 2472149753Sdes for (i = 0; s->x11_chanids[i] != -1; i++) { 2473149753Sdes debug("session_close_single_x11: session %d: " 2474149753Sdes "closing channel %d", s->self, s->x11_chanids[i]); 2475149753Sdes /* 2476149753Sdes * The channel "id" is already closing, but make sure we 2477149753Sdes * close all of its siblings. 2478149753Sdes */ 2479149753Sdes if (s->x11_chanids[i] != id) 2480149753Sdes session_close_x11(s->x11_chanids[i]); 2481149753Sdes } 2482255767Sdes free(s->x11_chanids); 2483149753Sdes s->x11_chanids = NULL; 2484255767Sdes free(s->display); 2485255767Sdes s->display = NULL; 2486255767Sdes free(s->auth_proto); 2487255767Sdes s->auth_proto = NULL; 2488255767Sdes free(s->auth_data); 2489255767Sdes s->auth_data = NULL; 2490255767Sdes free(s->auth_display); 2491255767Sdes s->auth_display = NULL; 2492149753Sdes} 2493149753Sdes 2494149753Sdesstatic void 249560573Skrissession_exit_message(Session *s, int status) 249660573Skris{ 249760573Skris Channel *c; 249892559Sdes 249992559Sdes if ((c = channel_lookup(s->chanid)) == NULL) 250092559Sdes fatal("session_exit_message: session %d: no channel %d", 250160573Skris s->self, s->chanid); 250298684Sdes debug("session_exit_message: session %d channel %d pid %ld", 250398684Sdes s->self, s->chanid, (long)s->pid); 250460573Skris 250560573Skris if (WIFEXITED(status)) { 250692559Sdes channel_request_start(s->chanid, "exit-status", 0); 250760573Skris packet_put_int(WEXITSTATUS(status)); 250860573Skris packet_send(); 250960573Skris } else if (WIFSIGNALED(status)) { 251092559Sdes channel_request_start(s->chanid, "exit-signal", 0); 2511106130Sdes packet_put_cstring(sig2name(WTERMSIG(status))); 251298941Sdes#ifdef WCOREDUMP 2513181111Sdes packet_put_char(WCOREDUMP(status)? 1 : 0); 251498941Sdes#else /* WCOREDUMP */ 251598941Sdes packet_put_char(0); 251698941Sdes#endif /* WCOREDUMP */ 251760573Skris packet_put_cstring(""); 251860573Skris packet_put_cstring(""); 251960573Skris packet_send(); 252060573Skris } else { 252160573Skris /* Some weird exit cause. Just exit. */ 252260573Skris packet_disconnect("wait returned status %04x.", status); 252360573Skris } 252460573Skris 252560573Skris /* disconnect channel */ 252660573Skris debug("session_exit_message: release channel %d", s->chanid); 2527157019Sdes 252860573Skris /* 2529157019Sdes * Adjust cleanup callback attachment to send close messages when 2530162856Sdes * the channel gets EOF. The session will be then be closed 2531157019Sdes * by session_close_by_channel when the childs close their fds. 2532157019Sdes */ 2533157019Sdes channel_register_cleanup(c->self, session_close_by_channel, 1); 2534157019Sdes 2535157019Sdes /* 253660573Skris * emulate a write failure with 'chan_write_failed', nobody will be 253760573Skris * interested in data we write. 253860573Skris * Note that we must not call 'chan_read_failed', since there could 253960573Skris * be some more data waiting in the pipe. 254060573Skris */ 254160573Skris if (c->ostate != CHAN_OUTPUT_CLOSED) 254260573Skris chan_write_failed(c); 254360573Skris} 254460573Skris 254598684Sdesvoid 254692559Sdessession_close(Session *s) 254760573Skris{ 2548323124Sdes struct ssh *ssh = active_state; /* XXX */ 2549149753Sdes u_int i; 2550137019Sdes 2551296781Sdes verbose("Close session: user %s from %.200s port %d id %d", 2552296781Sdes s->pw->pw_name, 2553323124Sdes ssh_remote_ipaddr(ssh), 2554323124Sdes ssh_remote_port(ssh), 2555296781Sdes s->self); 2556296781Sdes 2557126277Sdes if (s->ttyfd != -1) 255892559Sdes session_pty_cleanup(s); 2559255767Sdes free(s->term); 2560255767Sdes free(s->display); 2561255767Sdes free(s->x11_chanids); 2562255767Sdes free(s->auth_display); 2563255767Sdes free(s->auth_data); 2564255767Sdes free(s->auth_proto); 2565262566Sdes free(s->subsys); 2566162856Sdes if (s->env != NULL) { 2567162856Sdes for (i = 0; i < s->num_env; i++) { 2568255767Sdes free(s->env[i].name); 2569255767Sdes free(s->env[i].val); 2570162856Sdes } 2571255767Sdes free(s->env); 2572137019Sdes } 257360573Skris session_proctitle(s); 2574181111Sdes session_unused(s->self); 257560573Skris} 257660573Skris 257760573Skrisvoid 257860573Skrissession_close_by_pid(pid_t pid, int status) 257960573Skris{ 258060573Skris Session *s = session_by_pid(pid); 258160573Skris if (s == NULL) { 258298684Sdes debug("session_close_by_pid: no session for pid %ld", 258398684Sdes (long)pid); 258460573Skris return; 258560573Skris } 258660573Skris if (s->chanid != -1) 258760573Skris session_exit_message(s, status); 2588157019Sdes if (s->ttyfd != -1) 2589157019Sdes session_pty_cleanup(s); 2590162856Sdes s->pid = 0; 259160573Skris} 259260573Skris 259360573Skris/* 259460573Skris * this is called when a channel dies before 259560573Skris * the session 'child' itself dies 259660573Skris */ 259760573Skrisvoid 259860573Skrissession_close_by_channel(int id, void *arg) 259960573Skris{ 260060573Skris Session *s = session_by_channel(id); 2601157019Sdes u_int i; 2602149753Sdes 260360573Skris if (s == NULL) { 260492559Sdes debug("session_close_by_channel: no session for id %d", id); 260560573Skris return; 260660573Skris } 260798684Sdes debug("session_close_by_channel: channel %d child %ld", 260898684Sdes id, (long)s->pid); 260992559Sdes if (s->pid != 0) { 261092559Sdes debug("session_close_by_channel: channel %d: has child", id); 261192559Sdes /* 261292559Sdes * delay detach of session, but release pty, since 261392559Sdes * the fd's to the child are already closed 261492559Sdes */ 2615126277Sdes if (s->ttyfd != -1) 261692559Sdes session_pty_cleanup(s); 261792559Sdes return; 261892559Sdes } 261992559Sdes /* detach by removing callback */ 262060573Skris channel_cancel_cleanup(s->chanid); 2621157019Sdes 2622157019Sdes /* Close any X11 listeners associated with this session */ 2623157019Sdes if (s->x11_chanids != NULL) { 2624157019Sdes for (i = 0; s->x11_chanids[i] != -1; i++) { 2625157019Sdes session_close_x11(s->x11_chanids[i]); 2626157019Sdes s->x11_chanids[i] = -1; 2627157019Sdes } 2628157019Sdes } 2629157019Sdes 263060573Skris s->chanid = -1; 263192559Sdes session_close(s); 263292559Sdes} 263360573Skris 263492559Sdesvoid 263598684Sdessession_destroy_all(void (*closefunc)(Session *)) 263692559Sdes{ 263792559Sdes int i; 2638181111Sdes for (i = 0; i < sessions_nalloc; i++) { 263992559Sdes Session *s = &sessions[i]; 264098684Sdes if (s->used) { 264198684Sdes if (closefunc != NULL) 264298684Sdes closefunc(s); 264398684Sdes else 264498684Sdes session_close(s); 264598684Sdes } 264660573Skris } 264760573Skris} 264860573Skris 264992559Sdesstatic char * 265060573Skrissession_tty_list(void) 265160573Skris{ 265260573Skris static char buf[1024]; 265360573Skris int i; 2654113911Sdes char *cp; 2655113911Sdes 265660573Skris buf[0] = '\0'; 2657181111Sdes for (i = 0; i < sessions_nalloc; i++) { 265860573Skris Session *s = &sessions[i]; 265960573Skris if (s->used && s->ttyfd != -1) { 2660126277Sdes 2661113911Sdes if (strncmp(s->tty, "/dev/", 5) != 0) { 2662113911Sdes cp = strrchr(s->tty, '/'); 2663113911Sdes cp = (cp == NULL) ? s->tty : cp + 1; 2664113911Sdes } else 2665113911Sdes cp = s->tty + 5; 2666126277Sdes 266760573Skris if (buf[0] != '\0') 266860573Skris strlcat(buf, ",", sizeof buf); 2669113911Sdes strlcat(buf, cp, sizeof buf); 267060573Skris } 267160573Skris } 267260573Skris if (buf[0] == '\0') 267360573Skris strlcpy(buf, "notty", sizeof buf); 267460573Skris return buf; 267560573Skris} 267660573Skris 267760573Skrisvoid 267860573Skrissession_proctitle(Session *s) 267960573Skris{ 268060573Skris if (s->pw == NULL) 268160573Skris error("no user for session %d", s->self); 268260573Skris else 268360573Skris setproctitle("%s@%s", s->pw->pw_name, session_tty_list()); 268460573Skris} 268560573Skris 268692559Sdesint 268792559Sdessession_setup_x11fwd(Session *s) 268860573Skris{ 268992559Sdes struct stat st; 269092559Sdes char display[512], auth_display[512]; 2691295367Sdes char hostname[NI_MAXHOST]; 2692149753Sdes u_int i; 269365674Skris 269492559Sdes if (no_x11_forwarding_flag) { 269592559Sdes packet_send_debug("X11 forwarding disabled in user configuration file."); 269692559Sdes return 0; 269792559Sdes } 269892559Sdes if (!options.x11_forwarding) { 269992559Sdes debug("X11 forwarding disabled in server configuration file."); 270092559Sdes return 0; 270192559Sdes } 2702295367Sdes if (options.xauth_location == NULL || 270392559Sdes (stat(options.xauth_location, &st) == -1)) { 270492559Sdes packet_send_debug("No xauth program; cannot forward with spoofing."); 270592559Sdes return 0; 270692559Sdes } 270792559Sdes if (options.use_login) { 270892559Sdes packet_send_debug("X11 forwarding disabled; " 270992559Sdes "not compatible with UseLogin=yes."); 271092559Sdes return 0; 271192559Sdes } 271292559Sdes if (s->display != NULL) { 271392559Sdes debug("X11 display already set."); 271492559Sdes return 0; 271592559Sdes } 271699063Sdes if (x11_create_display_inet(options.x11_display_offset, 271799063Sdes options.x11_use_localhost, s->single_connection, 2718149753Sdes &s->display_number, &s->x11_chanids) == -1) { 271992559Sdes debug("x11_create_display_inet failed."); 272092559Sdes return 0; 272192559Sdes } 2722149753Sdes for (i = 0; s->x11_chanids[i] != -1; i++) { 2723149753Sdes channel_register_cleanup(s->x11_chanids[i], 2724157019Sdes session_close_single_x11, 0); 2725149753Sdes } 272692559Sdes 272792559Sdes /* Set up a suitable value for the DISPLAY variable. */ 272892559Sdes if (gethostname(hostname, sizeof(hostname)) < 0) 272992559Sdes fatal("gethostname: %.100s", strerror(errno)); 273092559Sdes /* 273192559Sdes * auth_display must be used as the displayname when the 273292559Sdes * authorization entry is added with xauth(1). This will be 273392559Sdes * different than the DISPLAY string for localhost displays. 273492559Sdes */ 273592559Sdes if (options.x11_use_localhost) { 273699063Sdes snprintf(display, sizeof display, "localhost:%u.%u", 273792559Sdes s->display_number, s->screen); 273899063Sdes snprintf(auth_display, sizeof auth_display, "unix:%u.%u", 273992559Sdes s->display_number, s->screen); 274092559Sdes s->display = xstrdup(display); 274192559Sdes s->auth_display = xstrdup(auth_display); 274292559Sdes } else { 274398941Sdes#ifdef IPADDR_IN_DISPLAY 274498941Sdes struct hostent *he; 274598941Sdes struct in_addr my_addr; 274698941Sdes 274798941Sdes he = gethostbyname(hostname); 274898941Sdes if (he == NULL) { 274998941Sdes error("Can't get IP address for X11 DISPLAY."); 275098941Sdes packet_send_debug("Can't get IP address for X11 DISPLAY."); 275198941Sdes return 0; 275298941Sdes } 275398941Sdes memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr)); 275499063Sdes snprintf(display, sizeof display, "%.50s:%u.%u", inet_ntoa(my_addr), 275598941Sdes s->display_number, s->screen); 275698941Sdes#else 275799063Sdes snprintf(display, sizeof display, "%.400s:%u.%u", hostname, 275892559Sdes s->display_number, s->screen); 275998941Sdes#endif 276092559Sdes s->display = xstrdup(display); 276192559Sdes s->auth_display = xstrdup(display); 276292559Sdes } 276392559Sdes 276492559Sdes return 1; 276560573Skris} 276692559Sdes 276792559Sdesstatic void 276892559Sdesdo_authenticated2(Authctxt *authctxt) 276992559Sdes{ 277092559Sdes server_loop2(authctxt); 2771126277Sdes} 2772126277Sdes 2773126277Sdesvoid 2774126277Sdesdo_cleanup(Authctxt *authctxt) 2775126277Sdes{ 2776126277Sdes static int called = 0; 2777126277Sdes 2778126277Sdes debug("do_cleanup"); 2779126277Sdes 2780126277Sdes /* no cleanup if we're in the child for login shell */ 2781126277Sdes if (is_child) 2782126277Sdes return; 2783126277Sdes 2784126277Sdes /* avoid double cleanup */ 2785126277Sdes if (called) 2786126277Sdes return; 2787126277Sdes called = 1; 2788126277Sdes 2789181111Sdes if (authctxt == NULL) 2790126277Sdes return; 2791181111Sdes 2792181111Sdes#ifdef USE_PAM 2793181111Sdes if (options.use_pam) { 2794181111Sdes sshpam_cleanup(); 2795181111Sdes sshpam_thread_cleanup(); 2796181111Sdes } 2797181111Sdes#endif 2798181111Sdes 2799181111Sdes if (!authctxt->authenticated) 2800181111Sdes return; 2801181111Sdes 2802126277Sdes#ifdef KRB5 2803126277Sdes if (options.kerberos_ticket_cleanup && 2804126277Sdes authctxt->krb5_ctx) 2805126277Sdes krb5_cleanup_proc(authctxt); 2806124211Sdes#endif 2807126277Sdes 2808126277Sdes#ifdef GSSAPI 2809126277Sdes if (compat20 && options.gss_cleanup_creds) 2810126277Sdes ssh_gssapi_cleanup_creds(); 2811126277Sdes#endif 2812126277Sdes 2813126277Sdes /* remove agent socket */ 2814126277Sdes auth_sock_cleanup_proc(authctxt->pw); 2815126277Sdes 2816126277Sdes /* 2817126277Sdes * Cleanup ptys/utmp only if privsep is disabled, 2818126277Sdes * or if running in monitor. 2819126277Sdes */ 2820126277Sdes if (!use_privsep || mm_is_monitor()) 2821126277Sdes session_destroy_all(session_pty_cleanup2); 282292559Sdes} 2823323124Sdes 2824323124Sdes/* Return a name for the remote host that fits inside utmp_size */ 2825323124Sdes 2826323124Sdesconst char * 2827323124Sdessession_get_remote_name_or_ip(struct ssh *ssh, u_int utmp_size, int use_dns) 2828323124Sdes{ 2829323124Sdes const char *remote = ""; 2830323124Sdes 2831323124Sdes if (utmp_size > 0) 2832323124Sdes remote = auth_get_canonical_hostname(ssh, use_dns); 2833323124Sdes if (utmp_size == 0 || strlen(remote) > utmp_size) 2834323124Sdes remote = ssh_remote_ipaddr(ssh); 2835323124Sdes return remote; 2836323124Sdes} 2837323124Sdes 2838