1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 3*0Sstevel@tonic-gate * All rights reserved 4*0Sstevel@tonic-gate * 5*0Sstevel@tonic-gate * As far as I am concerned, the code I have written for this software 6*0Sstevel@tonic-gate * can be used freely for any purpose. Any derived versions of this 7*0Sstevel@tonic-gate * software must be clearly marked as such, and if the derived work is 8*0Sstevel@tonic-gate * incompatible with the protocol description in the RFC file, it must be 9*0Sstevel@tonic-gate * called by a name other than "ssh" or "Secure Shell". 10*0Sstevel@tonic-gate * 11*0Sstevel@tonic-gate * SSH2 support by Markus Friedl. 12*0Sstevel@tonic-gate * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 15*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions 16*0Sstevel@tonic-gate * are met: 17*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 18*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 19*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 20*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 21*0Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 22*0Sstevel@tonic-gate * 23*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24*0Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25*0Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26*0Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27*0Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28*0Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29*0Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30*0Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31*0Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32*0Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33*0Sstevel@tonic-gate */ 34*0Sstevel@tonic-gate /* 35*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 36*0Sstevel@tonic-gate * Use is subject to license terms. 37*0Sstevel@tonic-gate */ 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate #include "includes.h" 40*0Sstevel@tonic-gate RCSID("$OpenBSD: session.c,v 1.150 2002/09/16 19:55:33 stevesk Exp $"); 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate #ifdef HAVE_DEFOPEN 45*0Sstevel@tonic-gate #include <deflt.h> 46*0Sstevel@tonic-gate #include <ulimit.h> 47*0Sstevel@tonic-gate #endif /* HAVE_DEFOPEN */ 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate #include "ssh.h" 50*0Sstevel@tonic-gate #include "ssh1.h" 51*0Sstevel@tonic-gate #include "ssh2.h" 52*0Sstevel@tonic-gate #include "xmalloc.h" 53*0Sstevel@tonic-gate #include "sshpty.h" 54*0Sstevel@tonic-gate #include "packet.h" 55*0Sstevel@tonic-gate #include "buffer.h" 56*0Sstevel@tonic-gate #include "mpaux.h" 57*0Sstevel@tonic-gate #include "uidswap.h" 58*0Sstevel@tonic-gate #include "compat.h" 59*0Sstevel@tonic-gate #include "channels.h" 60*0Sstevel@tonic-gate #include "bufaux.h" 61*0Sstevel@tonic-gate #include "auth.h" 62*0Sstevel@tonic-gate #include "auth-options.h" 63*0Sstevel@tonic-gate #include "pathnames.h" 64*0Sstevel@tonic-gate #include "log.h" 65*0Sstevel@tonic-gate #include "servconf.h" 66*0Sstevel@tonic-gate #include "sshlogin.h" 67*0Sstevel@tonic-gate #include "serverloop.h" 68*0Sstevel@tonic-gate #include "canohost.h" 69*0Sstevel@tonic-gate #include "session.h" 70*0Sstevel@tonic-gate #include "monitor_wrap.h" 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate #ifdef USE_PAM 73*0Sstevel@tonic-gate #include <security/pam_appl.h> 74*0Sstevel@tonic-gate #endif /* USE_PAM */ 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate #ifdef GSSAPI 77*0Sstevel@tonic-gate #include "ssh-gss.h" 78*0Sstevel@tonic-gate #endif 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate #ifdef ALTPRIVSEP 81*0Sstevel@tonic-gate #include "altprivsep.h" 82*0Sstevel@tonic-gate #endif /* ALTPRIVSEP */ 83*0Sstevel@tonic-gate 84*0Sstevel@tonic-gate #ifdef HAVE_CYGWIN 85*0Sstevel@tonic-gate #include <windows.h> 86*0Sstevel@tonic-gate #include <sys/cygwin.h> 87*0Sstevel@tonic-gate #define is_winnt (GetVersion() < 0x80000000) 88*0Sstevel@tonic-gate #endif 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate /* func */ 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate Session *session_new(void); 93*0Sstevel@tonic-gate void session_set_fds(Session *, int, int, int); 94*0Sstevel@tonic-gate void session_pty_cleanup(void *); 95*0Sstevel@tonic-gate void session_proctitle(Session *); 96*0Sstevel@tonic-gate int session_setup_x11fwd(Session *); 97*0Sstevel@tonic-gate void do_exec_pty(Session *, const char *); 98*0Sstevel@tonic-gate void do_exec_no_pty(Session *, const char *); 99*0Sstevel@tonic-gate void do_exec(Session *, const char *); 100*0Sstevel@tonic-gate void do_login(Session *, const char *); 101*0Sstevel@tonic-gate #ifdef LOGIN_NEEDS_UTMPX 102*0Sstevel@tonic-gate static void do_pre_login(Session *s); 103*0Sstevel@tonic-gate #endif 104*0Sstevel@tonic-gate void do_child(Session *, const char *); 105*0Sstevel@tonic-gate void do_motd(void); 106*0Sstevel@tonic-gate int check_quietlogin(Session *, const char *); 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate static void do_authenticated1(Authctxt *); 109*0Sstevel@tonic-gate static void do_authenticated2(Authctxt *); 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate static int session_pty_req(Session *); 112*0Sstevel@tonic-gate static int session_env_req(Session *s); 113*0Sstevel@tonic-gate static void session_free_env(char ***envp); 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate #ifdef USE_PAM 116*0Sstevel@tonic-gate static void session_do_pam(Session *, int); 117*0Sstevel@tonic-gate #endif /* USE_PAM */ 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate /* import */ 120*0Sstevel@tonic-gate extern ServerOptions options; 121*0Sstevel@tonic-gate extern char *__progname; 122*0Sstevel@tonic-gate extern int log_stderr; 123*0Sstevel@tonic-gate extern int debug_flag; 124*0Sstevel@tonic-gate extern u_int utmp_len; 125*0Sstevel@tonic-gate extern void destroy_sensitive_data(void); 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate #ifdef GSSAPI 128*0Sstevel@tonic-gate extern Gssctxt *xxx_gssctxt; 129*0Sstevel@tonic-gate #endif /* GSSAPI */ 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate /* original command from peer. */ 132*0Sstevel@tonic-gate const char *original_command = NULL; 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate /* data */ 135*0Sstevel@tonic-gate #define MAX_SESSIONS 10 136*0Sstevel@tonic-gate Session sessions[MAX_SESSIONS]; 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate #ifdef WITH_AIXAUTHENTICATE 139*0Sstevel@tonic-gate char *aixloginmsg; 140*0Sstevel@tonic-gate #endif /* WITH_AIXAUTHENTICATE */ 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate #ifdef HAVE_LOGIN_CAP 143*0Sstevel@tonic-gate login_cap_t *lc; 144*0Sstevel@tonic-gate #endif 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate /* Name and directory of socket for authentication agent forwarding. */ 147*0Sstevel@tonic-gate static char *auth_sock_name = NULL; 148*0Sstevel@tonic-gate static char *auth_sock_dir = NULL; 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate /* removes the agent forwarding socket */ 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gate static void 153*0Sstevel@tonic-gate auth_sock_cleanup_proc(void *_pw) 154*0Sstevel@tonic-gate { 155*0Sstevel@tonic-gate struct passwd *pw = _pw; 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate if (auth_sock_name != NULL) { 158*0Sstevel@tonic-gate temporarily_use_uid(pw); 159*0Sstevel@tonic-gate unlink(auth_sock_name); 160*0Sstevel@tonic-gate rmdir(auth_sock_dir); 161*0Sstevel@tonic-gate auth_sock_name = NULL; 162*0Sstevel@tonic-gate restore_uid(); 163*0Sstevel@tonic-gate } 164*0Sstevel@tonic-gate } 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate static int 167*0Sstevel@tonic-gate auth_input_request_forwarding(struct passwd * pw) 168*0Sstevel@tonic-gate { 169*0Sstevel@tonic-gate Channel *nc; 170*0Sstevel@tonic-gate int sock; 171*0Sstevel@tonic-gate struct sockaddr_un sunaddr; 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate if (auth_sock_name != NULL) { 174*0Sstevel@tonic-gate error("authentication forwarding requested twice."); 175*0Sstevel@tonic-gate return 0; 176*0Sstevel@tonic-gate } 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate /* Temporarily drop privileged uid for mkdir/bind. */ 179*0Sstevel@tonic-gate temporarily_use_uid(pw); 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate /* Allocate a buffer for the socket name, and format the name. */ 182*0Sstevel@tonic-gate auth_sock_name = xmalloc(MAXPATHLEN); 183*0Sstevel@tonic-gate auth_sock_dir = xmalloc(MAXPATHLEN); 184*0Sstevel@tonic-gate strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXX", MAXPATHLEN); 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate /* Create private directory for socket */ 187*0Sstevel@tonic-gate if (mkdtemp(auth_sock_dir) == NULL) { 188*0Sstevel@tonic-gate packet_send_debug("Agent forwarding disabled: " 189*0Sstevel@tonic-gate "mkdtemp() failed: %.100s", strerror(errno)); 190*0Sstevel@tonic-gate restore_uid(); 191*0Sstevel@tonic-gate xfree(auth_sock_name); 192*0Sstevel@tonic-gate xfree(auth_sock_dir); 193*0Sstevel@tonic-gate auth_sock_name = NULL; 194*0Sstevel@tonic-gate auth_sock_dir = NULL; 195*0Sstevel@tonic-gate return 0; 196*0Sstevel@tonic-gate } 197*0Sstevel@tonic-gate snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld", 198*0Sstevel@tonic-gate auth_sock_dir, (long) getpid()); 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate /* delete agent socket on fatal() */ 201*0Sstevel@tonic-gate fatal_add_cleanup(auth_sock_cleanup_proc, pw); 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate /* Create the socket. */ 204*0Sstevel@tonic-gate sock = socket(AF_UNIX, SOCK_STREAM, 0); 205*0Sstevel@tonic-gate if (sock < 0) 206*0Sstevel@tonic-gate packet_disconnect("socket: %.100s", strerror(errno)); 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate /* Bind it to the name. */ 209*0Sstevel@tonic-gate memset(&sunaddr, 0, sizeof(sunaddr)); 210*0Sstevel@tonic-gate sunaddr.sun_family = AF_UNIX; 211*0Sstevel@tonic-gate strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path)); 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) 214*0Sstevel@tonic-gate packet_disconnect("bind: %.100s", strerror(errno)); 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate /* Restore the privileged uid. */ 217*0Sstevel@tonic-gate restore_uid(); 218*0Sstevel@tonic-gate 219*0Sstevel@tonic-gate /* Start listening on the socket. */ 220*0Sstevel@tonic-gate if (listen(sock, 5) < 0) 221*0Sstevel@tonic-gate packet_disconnect("listen: %.100s", strerror(errno)); 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate /* Allocate a channel for the authentication agent socket. */ 224*0Sstevel@tonic-gate nc = channel_new("auth socket", 225*0Sstevel@tonic-gate SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, 226*0Sstevel@tonic-gate CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 227*0Sstevel@tonic-gate 0, xstrdup("auth socket"), 1); 228*0Sstevel@tonic-gate strlcpy(nc->path, auth_sock_name, sizeof(nc->path)); 229*0Sstevel@tonic-gate return 1; 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate void 234*0Sstevel@tonic-gate do_authenticated(Authctxt *authctxt) 235*0Sstevel@tonic-gate { 236*0Sstevel@tonic-gate /* setup the channel layer */ 237*0Sstevel@tonic-gate if (!no_port_forwarding_flag && options.allow_tcp_forwarding) 238*0Sstevel@tonic-gate channel_permit_all_opens(); 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate if (compat20) 241*0Sstevel@tonic-gate do_authenticated2(authctxt); 242*0Sstevel@tonic-gate else 243*0Sstevel@tonic-gate do_authenticated1(authctxt); 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate /* remove agent socket */ 246*0Sstevel@tonic-gate if (auth_sock_name != NULL) 247*0Sstevel@tonic-gate auth_sock_cleanup_proc(authctxt->pw); 248*0Sstevel@tonic-gate #ifdef KRB4 249*0Sstevel@tonic-gate if (options.kerberos_ticket_cleanup) 250*0Sstevel@tonic-gate krb4_cleanup_proc(authctxt); 251*0Sstevel@tonic-gate #endif 252*0Sstevel@tonic-gate #ifdef KRB5 253*0Sstevel@tonic-gate if (options.kerberos_ticket_cleanup) 254*0Sstevel@tonic-gate krb5_cleanup_proc(authctxt); 255*0Sstevel@tonic-gate #endif 256*0Sstevel@tonic-gate } 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate /* 259*0Sstevel@tonic-gate * Prepares for an interactive session. This is called after the user has 260*0Sstevel@tonic-gate * been successfully authenticated. During this message exchange, pseudo 261*0Sstevel@tonic-gate * terminals are allocated, X11, TCP/IP, and authentication agent forwardings 262*0Sstevel@tonic-gate * are requested, etc. 263*0Sstevel@tonic-gate */ 264*0Sstevel@tonic-gate static void 265*0Sstevel@tonic-gate do_authenticated1(Authctxt *authctxt) 266*0Sstevel@tonic-gate { 267*0Sstevel@tonic-gate Session *s; 268*0Sstevel@tonic-gate char *command; 269*0Sstevel@tonic-gate int success, type, screen_flag; 270*0Sstevel@tonic-gate int enable_compression_after_reply = 0; 271*0Sstevel@tonic-gate u_int proto_len, data_len, dlen, compression_level = 0; 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gate s = session_new(); 274*0Sstevel@tonic-gate s->authctxt = authctxt; 275*0Sstevel@tonic-gate s->pw = authctxt->pw; 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate /* 278*0Sstevel@tonic-gate * We stay in this loop until the client requests to execute a shell 279*0Sstevel@tonic-gate * or a command. 280*0Sstevel@tonic-gate */ 281*0Sstevel@tonic-gate for (;;) { 282*0Sstevel@tonic-gate success = 0; 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate /* Get a packet from the client. */ 285*0Sstevel@tonic-gate type = packet_read(); 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate /* Process the packet. */ 288*0Sstevel@tonic-gate switch (type) { 289*0Sstevel@tonic-gate case SSH_CMSG_REQUEST_COMPRESSION: 290*0Sstevel@tonic-gate compression_level = packet_get_int(); 291*0Sstevel@tonic-gate packet_check_eom(); 292*0Sstevel@tonic-gate if (compression_level < 1 || compression_level > 9) { 293*0Sstevel@tonic-gate packet_send_debug("Received illegal compression level %d.", 294*0Sstevel@tonic-gate compression_level); 295*0Sstevel@tonic-gate break; 296*0Sstevel@tonic-gate } 297*0Sstevel@tonic-gate if (!options.compression) { 298*0Sstevel@tonic-gate debug2("compression disabled"); 299*0Sstevel@tonic-gate break; 300*0Sstevel@tonic-gate } 301*0Sstevel@tonic-gate /* Enable compression after we have responded with SUCCESS. */ 302*0Sstevel@tonic-gate enable_compression_after_reply = 1; 303*0Sstevel@tonic-gate success = 1; 304*0Sstevel@tonic-gate break; 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate case SSH_CMSG_REQUEST_PTY: 307*0Sstevel@tonic-gate success = session_pty_req(s); 308*0Sstevel@tonic-gate break; 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate case SSH_CMSG_X11_REQUEST_FORWARDING: 311*0Sstevel@tonic-gate s->auth_proto = packet_get_string(&proto_len); 312*0Sstevel@tonic-gate s->auth_data = packet_get_string(&data_len); 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate screen_flag = packet_get_protocol_flags() & 315*0Sstevel@tonic-gate SSH_PROTOFLAG_SCREEN_NUMBER; 316*0Sstevel@tonic-gate debug2("SSH_PROTOFLAG_SCREEN_NUMBER: %d", screen_flag); 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate if (packet_remaining() == 4) { 319*0Sstevel@tonic-gate if (!screen_flag) 320*0Sstevel@tonic-gate debug2("Buggy client: " 321*0Sstevel@tonic-gate "X11 screen flag missing"); 322*0Sstevel@tonic-gate s->screen = packet_get_int(); 323*0Sstevel@tonic-gate } else { 324*0Sstevel@tonic-gate s->screen = 0; 325*0Sstevel@tonic-gate } 326*0Sstevel@tonic-gate packet_check_eom(); 327*0Sstevel@tonic-gate success = session_setup_x11fwd(s); 328*0Sstevel@tonic-gate if (!success) { 329*0Sstevel@tonic-gate xfree(s->auth_proto); 330*0Sstevel@tonic-gate xfree(s->auth_data); 331*0Sstevel@tonic-gate s->auth_proto = NULL; 332*0Sstevel@tonic-gate s->auth_data = NULL; 333*0Sstevel@tonic-gate } 334*0Sstevel@tonic-gate break; 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate case SSH_CMSG_AGENT_REQUEST_FORWARDING: 337*0Sstevel@tonic-gate if (no_agent_forwarding_flag || compat13) { 338*0Sstevel@tonic-gate debug("Authentication agent forwarding not permitted for this authentication."); 339*0Sstevel@tonic-gate break; 340*0Sstevel@tonic-gate } 341*0Sstevel@tonic-gate debug("Received authentication agent forwarding request."); 342*0Sstevel@tonic-gate success = auth_input_request_forwarding(s->pw); 343*0Sstevel@tonic-gate break; 344*0Sstevel@tonic-gate 345*0Sstevel@tonic-gate case SSH_CMSG_PORT_FORWARD_REQUEST: 346*0Sstevel@tonic-gate if (no_port_forwarding_flag) { 347*0Sstevel@tonic-gate debug("Port forwarding not permitted for this authentication."); 348*0Sstevel@tonic-gate break; 349*0Sstevel@tonic-gate } 350*0Sstevel@tonic-gate if (!options.allow_tcp_forwarding) { 351*0Sstevel@tonic-gate debug("Port forwarding not permitted."); 352*0Sstevel@tonic-gate break; 353*0Sstevel@tonic-gate } 354*0Sstevel@tonic-gate debug("Received TCP/IP port forwarding request."); 355*0Sstevel@tonic-gate channel_input_port_forward_request(s->pw->pw_uid == 0, options.gateway_ports); 356*0Sstevel@tonic-gate success = 1; 357*0Sstevel@tonic-gate break; 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate case SSH_CMSG_MAX_PACKET_SIZE: 360*0Sstevel@tonic-gate if (packet_set_maxsize(packet_get_int()) > 0) 361*0Sstevel@tonic-gate success = 1; 362*0Sstevel@tonic-gate break; 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate #if defined(AFS) || defined(KRB5) 365*0Sstevel@tonic-gate case SSH_CMSG_HAVE_KERBEROS_TGT: 366*0Sstevel@tonic-gate if (!options.kerberos_tgt_passing) { 367*0Sstevel@tonic-gate verbose("Kerberos TGT passing disabled."); 368*0Sstevel@tonic-gate } else { 369*0Sstevel@tonic-gate char *kdata = packet_get_string(&dlen); 370*0Sstevel@tonic-gate packet_check_eom(); 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate /* XXX - 0x41, see creds_to_radix version */ 373*0Sstevel@tonic-gate if (kdata[0] != 0x41) { 374*0Sstevel@tonic-gate #ifdef KRB5 375*0Sstevel@tonic-gate krb5_data tgt; 376*0Sstevel@tonic-gate tgt.data = kdata; 377*0Sstevel@tonic-gate tgt.length = dlen; 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate if (auth_krb5_tgt(s->authctxt, &tgt)) 380*0Sstevel@tonic-gate success = 1; 381*0Sstevel@tonic-gate else 382*0Sstevel@tonic-gate verbose("Kerberos v5 TGT refused for %.100s", s->authctxt->user); 383*0Sstevel@tonic-gate #endif /* KRB5 */ 384*0Sstevel@tonic-gate } else { 385*0Sstevel@tonic-gate #ifdef AFS 386*0Sstevel@tonic-gate if (auth_krb4_tgt(s->authctxt, kdata)) 387*0Sstevel@tonic-gate success = 1; 388*0Sstevel@tonic-gate else 389*0Sstevel@tonic-gate verbose("Kerberos v4 TGT refused for %.100s", s->authctxt->user); 390*0Sstevel@tonic-gate #endif /* AFS */ 391*0Sstevel@tonic-gate } 392*0Sstevel@tonic-gate xfree(kdata); 393*0Sstevel@tonic-gate } 394*0Sstevel@tonic-gate break; 395*0Sstevel@tonic-gate #endif /* AFS || KRB5 */ 396*0Sstevel@tonic-gate 397*0Sstevel@tonic-gate #ifdef AFS 398*0Sstevel@tonic-gate case SSH_CMSG_HAVE_AFS_TOKEN: 399*0Sstevel@tonic-gate if (!options.afs_token_passing || !k_hasafs()) { 400*0Sstevel@tonic-gate verbose("AFS token passing disabled."); 401*0Sstevel@tonic-gate } else { 402*0Sstevel@tonic-gate /* Accept AFS token. */ 403*0Sstevel@tonic-gate char *token = packet_get_string(&dlen); 404*0Sstevel@tonic-gate packet_check_eom(); 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate if (auth_afs_token(s->authctxt, token)) 407*0Sstevel@tonic-gate success = 1; 408*0Sstevel@tonic-gate else 409*0Sstevel@tonic-gate verbose("AFS token refused for %.100s", 410*0Sstevel@tonic-gate s->authctxt->user); 411*0Sstevel@tonic-gate xfree(token); 412*0Sstevel@tonic-gate } 413*0Sstevel@tonic-gate break; 414*0Sstevel@tonic-gate #endif /* AFS */ 415*0Sstevel@tonic-gate 416*0Sstevel@tonic-gate case SSH_CMSG_EXEC_SHELL: 417*0Sstevel@tonic-gate case SSH_CMSG_EXEC_CMD: 418*0Sstevel@tonic-gate if (type == SSH_CMSG_EXEC_CMD) { 419*0Sstevel@tonic-gate command = packet_get_string(&dlen); 420*0Sstevel@tonic-gate debug("Exec command '%.500s'", command); 421*0Sstevel@tonic-gate do_exec(s, command); 422*0Sstevel@tonic-gate xfree(command); 423*0Sstevel@tonic-gate } else { 424*0Sstevel@tonic-gate do_exec(s, NULL); 425*0Sstevel@tonic-gate } 426*0Sstevel@tonic-gate packet_check_eom(); 427*0Sstevel@tonic-gate session_close(s); 428*0Sstevel@tonic-gate return; 429*0Sstevel@tonic-gate 430*0Sstevel@tonic-gate default: 431*0Sstevel@tonic-gate /* 432*0Sstevel@tonic-gate * Any unknown messages in this phase are ignored, 433*0Sstevel@tonic-gate * and a failure message is returned. 434*0Sstevel@tonic-gate */ 435*0Sstevel@tonic-gate log("Unknown packet type received after authentication: %d", type); 436*0Sstevel@tonic-gate } 437*0Sstevel@tonic-gate packet_start(success ? SSH_SMSG_SUCCESS : SSH_SMSG_FAILURE); 438*0Sstevel@tonic-gate packet_send(); 439*0Sstevel@tonic-gate packet_write_wait(); 440*0Sstevel@tonic-gate 441*0Sstevel@tonic-gate /* Enable compression now that we have replied if appropriate. */ 442*0Sstevel@tonic-gate if (enable_compression_after_reply) { 443*0Sstevel@tonic-gate enable_compression_after_reply = 0; 444*0Sstevel@tonic-gate packet_start_compression(compression_level); 445*0Sstevel@tonic-gate } 446*0Sstevel@tonic-gate } 447*0Sstevel@tonic-gate } 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate /* 450*0Sstevel@tonic-gate * This is called to fork and execute a command when we have no tty. This 451*0Sstevel@tonic-gate * will call do_child from the child, and server_loop from the parent after 452*0Sstevel@tonic-gate * setting up file descriptors and such. 453*0Sstevel@tonic-gate */ 454*0Sstevel@tonic-gate void 455*0Sstevel@tonic-gate do_exec_no_pty(Session *s, const char *command) 456*0Sstevel@tonic-gate { 457*0Sstevel@tonic-gate pid_t pid; 458*0Sstevel@tonic-gate 459*0Sstevel@tonic-gate #ifdef USE_PIPES 460*0Sstevel@tonic-gate int pin[2], pout[2], perr[2]; 461*0Sstevel@tonic-gate /* Allocate pipes for communicating with the program. */ 462*0Sstevel@tonic-gate if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0) 463*0Sstevel@tonic-gate packet_disconnect("Could not create pipes: %.100s", 464*0Sstevel@tonic-gate strerror(errno)); 465*0Sstevel@tonic-gate #else /* USE_PIPES */ 466*0Sstevel@tonic-gate int inout[2], err[2]; 467*0Sstevel@tonic-gate /* Uses socket pairs to communicate with the program. */ 468*0Sstevel@tonic-gate if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 || 469*0Sstevel@tonic-gate socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) 470*0Sstevel@tonic-gate packet_disconnect("Could not create socket pairs: %.100s", 471*0Sstevel@tonic-gate strerror(errno)); 472*0Sstevel@tonic-gate #endif /* USE_PIPES */ 473*0Sstevel@tonic-gate if (s == NULL) 474*0Sstevel@tonic-gate fatal("do_exec_no_pty: no session"); 475*0Sstevel@tonic-gate 476*0Sstevel@tonic-gate session_proctitle(s); 477*0Sstevel@tonic-gate 478*0Sstevel@tonic-gate /* Fork the child. */ 479*0Sstevel@tonic-gate if ((pid = fork()) == 0) { 480*0Sstevel@tonic-gate fatal_remove_all_cleanups(); 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate /* Child. Reinitialize the log since the pid has changed. */ 483*0Sstevel@tonic-gate log_init(__progname, options.log_level, options.log_facility, log_stderr); 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate /* 486*0Sstevel@tonic-gate * Create a new session and process group since the 4.4BSD 487*0Sstevel@tonic-gate * setlogin() affects the entire process group. 488*0Sstevel@tonic-gate */ 489*0Sstevel@tonic-gate if (setsid() < 0) 490*0Sstevel@tonic-gate error("setsid failed: %.100s", strerror(errno)); 491*0Sstevel@tonic-gate 492*0Sstevel@tonic-gate #ifdef USE_PIPES 493*0Sstevel@tonic-gate /* 494*0Sstevel@tonic-gate * Redirect stdin. We close the parent side of the socket 495*0Sstevel@tonic-gate * pair, and make the child side the standard input. 496*0Sstevel@tonic-gate */ 497*0Sstevel@tonic-gate close(pin[1]); 498*0Sstevel@tonic-gate if (dup2(pin[0], 0) < 0) 499*0Sstevel@tonic-gate perror("dup2 stdin"); 500*0Sstevel@tonic-gate close(pin[0]); 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate /* Redirect stdout. */ 503*0Sstevel@tonic-gate close(pout[0]); 504*0Sstevel@tonic-gate if (dup2(pout[1], 1) < 0) 505*0Sstevel@tonic-gate perror("dup2 stdout"); 506*0Sstevel@tonic-gate close(pout[1]); 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate /* Redirect stderr. */ 509*0Sstevel@tonic-gate close(perr[0]); 510*0Sstevel@tonic-gate if (dup2(perr[1], 2) < 0) 511*0Sstevel@tonic-gate perror("dup2 stderr"); 512*0Sstevel@tonic-gate close(perr[1]); 513*0Sstevel@tonic-gate #else /* USE_PIPES */ 514*0Sstevel@tonic-gate /* 515*0Sstevel@tonic-gate * Redirect stdin, stdout, and stderr. Stdin and stdout will 516*0Sstevel@tonic-gate * use the same socket, as some programs (particularly rdist) 517*0Sstevel@tonic-gate * seem to depend on it. 518*0Sstevel@tonic-gate */ 519*0Sstevel@tonic-gate close(inout[1]); 520*0Sstevel@tonic-gate close(err[1]); 521*0Sstevel@tonic-gate if (dup2(inout[0], 0) < 0) /* stdin */ 522*0Sstevel@tonic-gate perror("dup2 stdin"); 523*0Sstevel@tonic-gate if (dup2(inout[0], 1) < 0) /* stdout. Note: same socket as stdin. */ 524*0Sstevel@tonic-gate perror("dup2 stdout"); 525*0Sstevel@tonic-gate if (dup2(err[0], 2) < 0) /* stderr */ 526*0Sstevel@tonic-gate perror("dup2 stderr"); 527*0Sstevel@tonic-gate #endif /* USE_PIPES */ 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate #ifdef _UNICOS 530*0Sstevel@tonic-gate cray_init_job(s->pw); /* set up cray jid and tmpdir */ 531*0Sstevel@tonic-gate #endif 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate /* Do processing for the child (exec command etc). */ 534*0Sstevel@tonic-gate do_child(s, command); 535*0Sstevel@tonic-gate /* NOTREACHED */ 536*0Sstevel@tonic-gate } 537*0Sstevel@tonic-gate #ifdef _UNICOS 538*0Sstevel@tonic-gate signal(WJSIGNAL, cray_job_termination_handler); 539*0Sstevel@tonic-gate #endif /* _UNICOS */ 540*0Sstevel@tonic-gate #ifdef HAVE_CYGWIN 541*0Sstevel@tonic-gate if (is_winnt) 542*0Sstevel@tonic-gate cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); 543*0Sstevel@tonic-gate #endif 544*0Sstevel@tonic-gate if (pid < 0) 545*0Sstevel@tonic-gate packet_disconnect("fork failed: %.100s", strerror(errno)); 546*0Sstevel@tonic-gate s->pid = pid; 547*0Sstevel@tonic-gate /* Set interactive/non-interactive mode. */ 548*0Sstevel@tonic-gate packet_set_interactive(s->display != NULL); 549*0Sstevel@tonic-gate #ifdef USE_PIPES 550*0Sstevel@tonic-gate /* We are the parent. Close the child sides of the pipes. */ 551*0Sstevel@tonic-gate close(pin[0]); 552*0Sstevel@tonic-gate close(pout[1]); 553*0Sstevel@tonic-gate close(perr[1]); 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate if (compat20) { 556*0Sstevel@tonic-gate session_set_fds(s, pin[1], pout[0], s->is_subsystem ? -1 : perr[0]); 557*0Sstevel@tonic-gate /* Don't close channel before sending exit-status! */ 558*0Sstevel@tonic-gate channel_set_wait_for_exit(s->chanid, 1); 559*0Sstevel@tonic-gate } else { 560*0Sstevel@tonic-gate /* Enter the interactive session. */ 561*0Sstevel@tonic-gate server_loop(pid, pin[1], pout[0], perr[0]); 562*0Sstevel@tonic-gate /* server_loop has closed pin[1], pout[0], and perr[0]. */ 563*0Sstevel@tonic-gate } 564*0Sstevel@tonic-gate #else /* USE_PIPES */ 565*0Sstevel@tonic-gate /* We are the parent. Close the child sides of the socket pairs. */ 566*0Sstevel@tonic-gate close(inout[0]); 567*0Sstevel@tonic-gate close(err[0]); 568*0Sstevel@tonic-gate 569*0Sstevel@tonic-gate /* 570*0Sstevel@tonic-gate * Enter the interactive session. Note: server_loop must be able to 571*0Sstevel@tonic-gate * handle the case that fdin and fdout are the same. 572*0Sstevel@tonic-gate */ 573*0Sstevel@tonic-gate if (compat20) { 574*0Sstevel@tonic-gate session_set_fds(s, inout[1], inout[1], s->is_subsystem ? -1 : err[1]); 575*0Sstevel@tonic-gate /* Don't close channel before sending exit-status! */ 576*0Sstevel@tonic-gate channel_set_wait_for_exit(s->chanid, 1); 577*0Sstevel@tonic-gate } else { 578*0Sstevel@tonic-gate server_loop(pid, inout[1], inout[1], err[1]); 579*0Sstevel@tonic-gate /* server_loop has closed inout[1] and err[1]. */ 580*0Sstevel@tonic-gate } 581*0Sstevel@tonic-gate #endif /* USE_PIPES */ 582*0Sstevel@tonic-gate } 583*0Sstevel@tonic-gate 584*0Sstevel@tonic-gate /* 585*0Sstevel@tonic-gate * This is called to fork and execute a command when we have a tty. This 586*0Sstevel@tonic-gate * will call do_child from the child, and server_loop from the parent after 587*0Sstevel@tonic-gate * setting up file descriptors, controlling tty, updating wtmp, utmp, 588*0Sstevel@tonic-gate * lastlog, and other such operations. 589*0Sstevel@tonic-gate */ 590*0Sstevel@tonic-gate void 591*0Sstevel@tonic-gate do_exec_pty(Session *s, const char *command) 592*0Sstevel@tonic-gate { 593*0Sstevel@tonic-gate int fdout, ptyfd, ttyfd, ptymaster, pipe_fds[2]; 594*0Sstevel@tonic-gate pid_t pid; 595*0Sstevel@tonic-gate 596*0Sstevel@tonic-gate if (s == NULL) 597*0Sstevel@tonic-gate fatal("do_exec_pty: no session"); 598*0Sstevel@tonic-gate ptyfd = s->ptyfd; 599*0Sstevel@tonic-gate ttyfd = s->ttyfd; 600*0Sstevel@tonic-gate 601*0Sstevel@tonic-gate #ifdef USE_PAM 602*0Sstevel@tonic-gate session_do_pam(s, 1); /* pam_open_session() */ 603*0Sstevel@tonic-gate #endif /* USE_PAM */ 604*0Sstevel@tonic-gate 605*0Sstevel@tonic-gate /* 606*0Sstevel@tonic-gate * This pipe lets sshd wait for child to exec or exit. This is 607*0Sstevel@tonic-gate * particularly important for ALTPRIVSEP because the child is 608*0Sstevel@tonic-gate * the one to call the monitor to request a record_login() and 609*0Sstevel@tonic-gate * we don't want the child and the parent to compete for the 610*0Sstevel@tonic-gate * monitor's attention. But this is generic code and doesn't 611*0Sstevel@tonic-gate * hurt to have here even if ALTPRIVSEP is not used. 612*0Sstevel@tonic-gate */ 613*0Sstevel@tonic-gate if (pipe(pipe_fds) != 0) 614*0Sstevel@tonic-gate packet_disconnect("pipe failed: %.100s", strerror(errno)); 615*0Sstevel@tonic-gate 616*0Sstevel@tonic-gate (void) fcntl(pipe_fds[0], F_SETFD, FD_CLOEXEC); 617*0Sstevel@tonic-gate (void) fcntl(pipe_fds[1], F_SETFD, FD_CLOEXEC); 618*0Sstevel@tonic-gate 619*0Sstevel@tonic-gate /* Fork the child. */ 620*0Sstevel@tonic-gate if ((pid = fork()) == 0) { 621*0Sstevel@tonic-gate (void) close(pipe_fds[0]); 622*0Sstevel@tonic-gate 623*0Sstevel@tonic-gate fatal_remove_all_cleanups(); 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate /* Child. Reinitialize the log because the pid has changed. */ 626*0Sstevel@tonic-gate log_init(__progname, options.log_level, options.log_facility, log_stderr); 627*0Sstevel@tonic-gate /* Close the master side of the pseudo tty. */ 628*0Sstevel@tonic-gate close(ptyfd); 629*0Sstevel@tonic-gate 630*0Sstevel@tonic-gate /* Make the pseudo tty our controlling tty. */ 631*0Sstevel@tonic-gate pty_make_controlling_tty(&ttyfd, s->tty); 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gate /* Redirect stdin/stdout/stderr from the pseudo tty. */ 634*0Sstevel@tonic-gate if (dup2(ttyfd, 0) < 0) 635*0Sstevel@tonic-gate error("dup2 stdin: %s", strerror(errno)); 636*0Sstevel@tonic-gate if (dup2(ttyfd, 1) < 0) 637*0Sstevel@tonic-gate error("dup2 stdout: %s", strerror(errno)); 638*0Sstevel@tonic-gate if (dup2(ttyfd, 2) < 0) 639*0Sstevel@tonic-gate error("dup2 stderr: %s", strerror(errno)); 640*0Sstevel@tonic-gate 641*0Sstevel@tonic-gate /* Close the extra descriptor for the pseudo tty. */ 642*0Sstevel@tonic-gate close(ttyfd); 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gate /* record login, etc. similar to login(1) */ 645*0Sstevel@tonic-gate #if !defined(HAVE_OSF_SIA) 646*0Sstevel@tonic-gate if (!(options.use_login && command == NULL)) { 647*0Sstevel@tonic-gate #ifdef _UNICOS 648*0Sstevel@tonic-gate cray_init_job(s->pw); /* set up cray jid and tmpdir */ 649*0Sstevel@tonic-gate #endif /* _UNICOS */ 650*0Sstevel@tonic-gate do_login(s, command); 651*0Sstevel@tonic-gate } 652*0Sstevel@tonic-gate # ifdef LOGIN_NEEDS_UTMPX 653*0Sstevel@tonic-gate else 654*0Sstevel@tonic-gate do_pre_login(s); 655*0Sstevel@tonic-gate # endif 656*0Sstevel@tonic-gate #endif /* !HAVE_OSF_SIA */ 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate /* 659*0Sstevel@tonic-gate * do_pre_login() will have completed the record_login(), so 660*0Sstevel@tonic-gate * close the pipe to the parent so it can re-enter its event 661*0Sstevel@tonic-gate * loop and service the ptm; if enough debug messages get 662*0Sstevel@tonic-gate * written to the pty before this happens there will be a 663*0Sstevel@tonic-gate * deadlock. 664*0Sstevel@tonic-gate */ 665*0Sstevel@tonic-gate close(pipe_fds[1]); 666*0Sstevel@tonic-gate 667*0Sstevel@tonic-gate /* Do common processing for the child, such as execing the command. */ 668*0Sstevel@tonic-gate do_child(s, command); 669*0Sstevel@tonic-gate /* NOTREACHED */ 670*0Sstevel@tonic-gate } 671*0Sstevel@tonic-gate 672*0Sstevel@tonic-gate /* Wait for child to exec() or exit() */ 673*0Sstevel@tonic-gate (void) close(pipe_fds[1]); 674*0Sstevel@tonic-gate (void) read(pipe_fds[0], &pipe_fds[1], sizeof(int)); 675*0Sstevel@tonic-gate 676*0Sstevel@tonic-gate #ifdef _UNICOS 677*0Sstevel@tonic-gate signal(WJSIGNAL, cray_job_termination_handler); 678*0Sstevel@tonic-gate #endif /* _UNICOS */ 679*0Sstevel@tonic-gate #ifdef HAVE_CYGWIN 680*0Sstevel@tonic-gate if (is_winnt) 681*0Sstevel@tonic-gate cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); 682*0Sstevel@tonic-gate #endif 683*0Sstevel@tonic-gate if (pid < 0) 684*0Sstevel@tonic-gate packet_disconnect("fork failed: %.100s", strerror(errno)); 685*0Sstevel@tonic-gate s->pid = pid; 686*0Sstevel@tonic-gate 687*0Sstevel@tonic-gate /* Parent. Close the slave side of the pseudo tty. */ 688*0Sstevel@tonic-gate close(ttyfd); 689*0Sstevel@tonic-gate 690*0Sstevel@tonic-gate /* 691*0Sstevel@tonic-gate * Create another descriptor of the pty master side for use as the 692*0Sstevel@tonic-gate * standard input. We could use the original descriptor, but this 693*0Sstevel@tonic-gate * simplifies code in server_loop. The descriptor is bidirectional. 694*0Sstevel@tonic-gate */ 695*0Sstevel@tonic-gate fdout = dup(ptyfd); 696*0Sstevel@tonic-gate if (fdout < 0) 697*0Sstevel@tonic-gate packet_disconnect("dup #1 failed: %.100s", strerror(errno)); 698*0Sstevel@tonic-gate 699*0Sstevel@tonic-gate /* we keep a reference to the pty master */ 700*0Sstevel@tonic-gate ptymaster = dup(ptyfd); 701*0Sstevel@tonic-gate if (ptymaster < 0) 702*0Sstevel@tonic-gate packet_disconnect("dup #2 failed: %.100s", strerror(errno)); 703*0Sstevel@tonic-gate s->ptymaster = ptymaster; 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate /* Enter interactive session. */ 706*0Sstevel@tonic-gate packet_set_interactive(1); 707*0Sstevel@tonic-gate if (compat20) { 708*0Sstevel@tonic-gate session_set_fds(s, ptyfd, fdout, -1); 709*0Sstevel@tonic-gate /* Don't close channel before sending exit-status! */ 710*0Sstevel@tonic-gate channel_set_wait_for_exit(s->chanid, 1); 711*0Sstevel@tonic-gate } else { 712*0Sstevel@tonic-gate server_loop(pid, ptyfd, fdout, -1); 713*0Sstevel@tonic-gate /* server_loop _has_ closed ptyfd and fdout. */ 714*0Sstevel@tonic-gate } 715*0Sstevel@tonic-gate } 716*0Sstevel@tonic-gate 717*0Sstevel@tonic-gate #ifdef LOGIN_NEEDS_UTMPX 718*0Sstevel@tonic-gate static void 719*0Sstevel@tonic-gate do_pre_login(Session *s) 720*0Sstevel@tonic-gate { 721*0Sstevel@tonic-gate socklen_t fromlen; 722*0Sstevel@tonic-gate struct sockaddr_storage from; 723*0Sstevel@tonic-gate pid_t pid = getpid(); 724*0Sstevel@tonic-gate 725*0Sstevel@tonic-gate /* 726*0Sstevel@tonic-gate * Get IP address of client. If the connection is not a socket, let 727*0Sstevel@tonic-gate * the address be 0.0.0.0. 728*0Sstevel@tonic-gate */ 729*0Sstevel@tonic-gate memset(&from, 0, sizeof(from)); 730*0Sstevel@tonic-gate fromlen = sizeof(from); 731*0Sstevel@tonic-gate if (packet_connection_is_on_socket()) { 732*0Sstevel@tonic-gate if (getpeername(packet_get_connection_in(), 733*0Sstevel@tonic-gate (struct sockaddr *) & from, &fromlen) < 0) { 734*0Sstevel@tonic-gate debug("getpeername: %.100s", strerror(errno)); 735*0Sstevel@tonic-gate fatal_cleanup(); 736*0Sstevel@tonic-gate } 737*0Sstevel@tonic-gate } 738*0Sstevel@tonic-gate 739*0Sstevel@tonic-gate record_utmp_only(pid, s->tty, s->pw->pw_name, 740*0Sstevel@tonic-gate get_remote_name_or_ip(utmp_len, options.verify_reverse_mapping), 741*0Sstevel@tonic-gate (struct sockaddr *)&from); 742*0Sstevel@tonic-gate } 743*0Sstevel@tonic-gate #endif 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate /* 746*0Sstevel@tonic-gate * This is called to fork and execute a command. If another command is 747*0Sstevel@tonic-gate * to be forced, execute that instead. 748*0Sstevel@tonic-gate */ 749*0Sstevel@tonic-gate void 750*0Sstevel@tonic-gate do_exec(Session *s, const char *command) 751*0Sstevel@tonic-gate { 752*0Sstevel@tonic-gate if (command) 753*0Sstevel@tonic-gate s->command = xstrdup(command); 754*0Sstevel@tonic-gate 755*0Sstevel@tonic-gate if (forced_command) { 756*0Sstevel@tonic-gate original_command = command; 757*0Sstevel@tonic-gate command = forced_command; 758*0Sstevel@tonic-gate debug("Forced command '%.900s'", command); 759*0Sstevel@tonic-gate } 760*0Sstevel@tonic-gate 761*0Sstevel@tonic-gate if (s->ttyfd != -1) 762*0Sstevel@tonic-gate do_exec_pty(s, command); 763*0Sstevel@tonic-gate else 764*0Sstevel@tonic-gate do_exec_no_pty(s, command); 765*0Sstevel@tonic-gate 766*0Sstevel@tonic-gate original_command = NULL; 767*0Sstevel@tonic-gate } 768*0Sstevel@tonic-gate 769*0Sstevel@tonic-gate 770*0Sstevel@tonic-gate /* administrative, login(1)-like work */ 771*0Sstevel@tonic-gate void 772*0Sstevel@tonic-gate do_login(Session *s, const char *command) 773*0Sstevel@tonic-gate { 774*0Sstevel@tonic-gate char *time_string; 775*0Sstevel@tonic-gate #ifndef ALTPRIVSEP 776*0Sstevel@tonic-gate struct passwd * pw = s->pw; 777*0Sstevel@tonic-gate #endif /* ALTPRIVSEP*/ 778*0Sstevel@tonic-gate pid_t pid = getpid(); 779*0Sstevel@tonic-gate 780*0Sstevel@tonic-gate /* Record that there was a login on that tty from the remote host. */ 781*0Sstevel@tonic-gate #ifdef ALTPRIVSEP 782*0Sstevel@tonic-gate debug3("Recording SSHv2 channel login in utmpx/wtmpx"); 783*0Sstevel@tonic-gate altprivsep_record_login(pid, s->tty); 784*0Sstevel@tonic-gate #else /* ALTPRIVSEP*/ 785*0Sstevel@tonic-gate if (!use_privsep) { 786*0Sstevel@tonic-gate debug3("Recording SSHv2 channel login in utmpx/wtmpx"); 787*0Sstevel@tonic-gate record_login(pid, s->tty, NULL, pw->pw_name); 788*0Sstevel@tonic-gate } 789*0Sstevel@tonic-gate #endif /* ALTPRIVSEP*/ 790*0Sstevel@tonic-gate 791*0Sstevel@tonic-gate if (check_quietlogin(s, command)) 792*0Sstevel@tonic-gate return; 793*0Sstevel@tonic-gate 794*0Sstevel@tonic-gate #ifdef USE_PAM 795*0Sstevel@tonic-gate print_pam_messages(); 796*0Sstevel@tonic-gate #endif /* USE_PAM */ 797*0Sstevel@tonic-gate #ifdef WITH_AIXAUTHENTICATE 798*0Sstevel@tonic-gate if (aixloginmsg && *aixloginmsg) 799*0Sstevel@tonic-gate printf("%s\n", aixloginmsg); 800*0Sstevel@tonic-gate #endif /* WITH_AIXAUTHENTICATE */ 801*0Sstevel@tonic-gate 802*0Sstevel@tonic-gate #ifndef NO_SSH_LASTLOG 803*0Sstevel@tonic-gate if (options.print_lastlog && s->last_login_time != 0) { 804*0Sstevel@tonic-gate time_string = ctime(&s->last_login_time); 805*0Sstevel@tonic-gate if (strchr(time_string, '\n')) 806*0Sstevel@tonic-gate *strchr(time_string, '\n') = 0; 807*0Sstevel@tonic-gate if (strcmp(s->hostname, "") == 0) 808*0Sstevel@tonic-gate printf("Last login: %s\r\n", time_string); 809*0Sstevel@tonic-gate else 810*0Sstevel@tonic-gate printf("Last login: %s from %s\r\n", time_string, 811*0Sstevel@tonic-gate s->hostname); 812*0Sstevel@tonic-gate } 813*0Sstevel@tonic-gate #endif /* NO_SSH_LASTLOG */ 814*0Sstevel@tonic-gate 815*0Sstevel@tonic-gate do_motd(); 816*0Sstevel@tonic-gate } 817*0Sstevel@tonic-gate 818*0Sstevel@tonic-gate /* 819*0Sstevel@tonic-gate * Display the message of the day. 820*0Sstevel@tonic-gate */ 821*0Sstevel@tonic-gate void 822*0Sstevel@tonic-gate do_motd(void) 823*0Sstevel@tonic-gate { 824*0Sstevel@tonic-gate FILE *f; 825*0Sstevel@tonic-gate char buf[256]; 826*0Sstevel@tonic-gate 827*0Sstevel@tonic-gate if (options.print_motd) { 828*0Sstevel@tonic-gate #ifdef HAVE_LOGIN_CAP 829*0Sstevel@tonic-gate f = fopen(login_getcapstr(lc, "welcome", "/etc/motd", 830*0Sstevel@tonic-gate "/etc/motd"), "r"); 831*0Sstevel@tonic-gate #else 832*0Sstevel@tonic-gate f = fopen("/etc/motd", "r"); 833*0Sstevel@tonic-gate #endif 834*0Sstevel@tonic-gate if (f) { 835*0Sstevel@tonic-gate while (fgets(buf, sizeof(buf), f)) 836*0Sstevel@tonic-gate fputs(buf, stdout); 837*0Sstevel@tonic-gate fclose(f); 838*0Sstevel@tonic-gate } 839*0Sstevel@tonic-gate } 840*0Sstevel@tonic-gate } 841*0Sstevel@tonic-gate 842*0Sstevel@tonic-gate 843*0Sstevel@tonic-gate /* 844*0Sstevel@tonic-gate * Check for quiet login, either .hushlogin or command given. 845*0Sstevel@tonic-gate */ 846*0Sstevel@tonic-gate int 847*0Sstevel@tonic-gate check_quietlogin(Session *s, const char *command) 848*0Sstevel@tonic-gate { 849*0Sstevel@tonic-gate char buf[256]; 850*0Sstevel@tonic-gate struct passwd *pw = s->pw; 851*0Sstevel@tonic-gate struct stat st; 852*0Sstevel@tonic-gate 853*0Sstevel@tonic-gate /* Return 1 if .hushlogin exists or a command given. */ 854*0Sstevel@tonic-gate if (command != NULL) 855*0Sstevel@tonic-gate return 1; 856*0Sstevel@tonic-gate snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir); 857*0Sstevel@tonic-gate #ifdef HAVE_LOGIN_CAP 858*0Sstevel@tonic-gate if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0) 859*0Sstevel@tonic-gate return 1; 860*0Sstevel@tonic-gate #else 861*0Sstevel@tonic-gate if (stat(buf, &st) >= 0) 862*0Sstevel@tonic-gate return 1; 863*0Sstevel@tonic-gate #endif 864*0Sstevel@tonic-gate return 0; 865*0Sstevel@tonic-gate } 866*0Sstevel@tonic-gate 867*0Sstevel@tonic-gate /* 868*0Sstevel@tonic-gate * Sets the value of the given variable in the environment. If the variable 869*0Sstevel@tonic-gate * already exists, its value is overriden. 870*0Sstevel@tonic-gate */ 871*0Sstevel@tonic-gate void 872*0Sstevel@tonic-gate child_set_env(char ***envp, u_int *envsizep, const char *name, 873*0Sstevel@tonic-gate const char *value) 874*0Sstevel@tonic-gate { 875*0Sstevel@tonic-gate u_int i, namelen; 876*0Sstevel@tonic-gate char **env; 877*0Sstevel@tonic-gate 878*0Sstevel@tonic-gate debug3("child_set_env(%s, %s)", name, value); 879*0Sstevel@tonic-gate /* 880*0Sstevel@tonic-gate * Find the slot where the value should be stored. If the variable 881*0Sstevel@tonic-gate * already exists, we reuse the slot; otherwise we append a new slot 882*0Sstevel@tonic-gate * at the end of the array, expanding if necessary. 883*0Sstevel@tonic-gate */ 884*0Sstevel@tonic-gate env = *envp; 885*0Sstevel@tonic-gate namelen = strlen(name); 886*0Sstevel@tonic-gate for (i = 0; env[i]; i++) 887*0Sstevel@tonic-gate if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=') 888*0Sstevel@tonic-gate break; 889*0Sstevel@tonic-gate if (env[i]) { 890*0Sstevel@tonic-gate /* Reuse the slot. */ 891*0Sstevel@tonic-gate xfree(env[i]); 892*0Sstevel@tonic-gate } else { 893*0Sstevel@tonic-gate /* New variable. Expand if necessary. */ 894*0Sstevel@tonic-gate if (i >= (*envsizep) - 1) { 895*0Sstevel@tonic-gate if (*envsizep >= 1000) 896*0Sstevel@tonic-gate fatal("child_set_env: too many env vars," 897*0Sstevel@tonic-gate " skipping: %.100s", name); 898*0Sstevel@tonic-gate (*envsizep) += 50; 899*0Sstevel@tonic-gate env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *)); 900*0Sstevel@tonic-gate } 901*0Sstevel@tonic-gate /* Need to set the NULL pointer at end of array beyond the new slot. */ 902*0Sstevel@tonic-gate env[i + 1] = NULL; 903*0Sstevel@tonic-gate } 904*0Sstevel@tonic-gate 905*0Sstevel@tonic-gate /* Allocate space and format the variable in the appropriate slot. */ 906*0Sstevel@tonic-gate env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1); 907*0Sstevel@tonic-gate snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value); 908*0Sstevel@tonic-gate } 909*0Sstevel@tonic-gate 910*0Sstevel@tonic-gate /* 911*0Sstevel@tonic-gate * Reads environment variables from the given file and adds/overrides them 912*0Sstevel@tonic-gate * into the environment. If the file does not exist, this does nothing. 913*0Sstevel@tonic-gate * Otherwise, it must consist of empty lines, comments (line starts with '#') 914*0Sstevel@tonic-gate * and assignments of the form name=value. No other forms are allowed. 915*0Sstevel@tonic-gate */ 916*0Sstevel@tonic-gate static void 917*0Sstevel@tonic-gate read_environment_file(char ***env, u_int *envsize, 918*0Sstevel@tonic-gate const char *filename) 919*0Sstevel@tonic-gate { 920*0Sstevel@tonic-gate FILE *f; 921*0Sstevel@tonic-gate char buf[4096]; 922*0Sstevel@tonic-gate char *cp, *value; 923*0Sstevel@tonic-gate u_int lineno = 0; 924*0Sstevel@tonic-gate 925*0Sstevel@tonic-gate f = fopen(filename, "r"); 926*0Sstevel@tonic-gate if (!f) 927*0Sstevel@tonic-gate return; 928*0Sstevel@tonic-gate 929*0Sstevel@tonic-gate while (fgets(buf, sizeof(buf), f)) { 930*0Sstevel@tonic-gate if (++lineno > 1000) 931*0Sstevel@tonic-gate fatal("Too many lines in environment file %s", filename); 932*0Sstevel@tonic-gate for (cp = buf; *cp == ' ' || *cp == '\t'; cp++) 933*0Sstevel@tonic-gate ; 934*0Sstevel@tonic-gate if (!*cp || *cp == '#' || *cp == '\n') 935*0Sstevel@tonic-gate continue; 936*0Sstevel@tonic-gate if (strchr(cp, '\n')) 937*0Sstevel@tonic-gate *strchr(cp, '\n') = '\0'; 938*0Sstevel@tonic-gate value = strchr(cp, '='); 939*0Sstevel@tonic-gate if (value == NULL) { 940*0Sstevel@tonic-gate fprintf(stderr, gettext("Bad line %u in %.100s\n"), 941*0Sstevel@tonic-gate lineno, filename); 942*0Sstevel@tonic-gate continue; 943*0Sstevel@tonic-gate } 944*0Sstevel@tonic-gate /* 945*0Sstevel@tonic-gate * Replace the equals sign by nul, and advance value to 946*0Sstevel@tonic-gate * the value string. 947*0Sstevel@tonic-gate */ 948*0Sstevel@tonic-gate *value = '\0'; 949*0Sstevel@tonic-gate value++; 950*0Sstevel@tonic-gate child_set_env(env, envsize, cp, value); 951*0Sstevel@tonic-gate } 952*0Sstevel@tonic-gate fclose(f); 953*0Sstevel@tonic-gate } 954*0Sstevel@tonic-gate 955*0Sstevel@tonic-gate void copy_environment(char **source, char ***env, u_int *envsize) 956*0Sstevel@tonic-gate { 957*0Sstevel@tonic-gate char *var_name, *var_val; 958*0Sstevel@tonic-gate int i; 959*0Sstevel@tonic-gate 960*0Sstevel@tonic-gate if (source == NULL) 961*0Sstevel@tonic-gate return; 962*0Sstevel@tonic-gate 963*0Sstevel@tonic-gate for(i = 0; source[i] != NULL; i++) { 964*0Sstevel@tonic-gate var_name = xstrdup(source[i]); 965*0Sstevel@tonic-gate if ((var_val = strstr(var_name, "=")) == NULL) { 966*0Sstevel@tonic-gate xfree(var_name); 967*0Sstevel@tonic-gate continue; 968*0Sstevel@tonic-gate } 969*0Sstevel@tonic-gate *var_val++ = '\0'; 970*0Sstevel@tonic-gate 971*0Sstevel@tonic-gate debug3("Copy environment: %s=%s", var_name, var_val); 972*0Sstevel@tonic-gate child_set_env(env, envsize, var_name, var_val); 973*0Sstevel@tonic-gate 974*0Sstevel@tonic-gate xfree(var_name); 975*0Sstevel@tonic-gate } 976*0Sstevel@tonic-gate } 977*0Sstevel@tonic-gate 978*0Sstevel@tonic-gate #ifdef HAVE_DEFOPEN 979*0Sstevel@tonic-gate static 980*0Sstevel@tonic-gate void 981*0Sstevel@tonic-gate deflt_do_setup_env(Session *s, const char *shell, char ***env, u_int *envsize) 982*0Sstevel@tonic-gate { 983*0Sstevel@tonic-gate int flags; 984*0Sstevel@tonic-gate char *ptr; 985*0Sstevel@tonic-gate mode_t Umask = 022; 986*0Sstevel@tonic-gate 987*0Sstevel@tonic-gate if (defopen(_PATH_DEFAULT_LOGIN)) 988*0Sstevel@tonic-gate return; 989*0Sstevel@tonic-gate 990*0Sstevel@tonic-gate /* Ignore case */ 991*0Sstevel@tonic-gate flags = defcntl(DC_GETFLAGS, 0); 992*0Sstevel@tonic-gate TURNOFF(flags, DC_CASE); 993*0Sstevel@tonic-gate (void) defcntl(DC_SETFLAGS, flags); 994*0Sstevel@tonic-gate 995*0Sstevel@tonic-gate /* TZ & HZ */ 996*0Sstevel@tonic-gate if ((ptr = defread("TIMEZONE=")) != NULL) 997*0Sstevel@tonic-gate child_set_env(env, envsize, "TZ", ptr); 998*0Sstevel@tonic-gate if ((ptr = defread("HZ=")) != NULL) 999*0Sstevel@tonic-gate child_set_env(env, envsize, "HZ", ptr); 1000*0Sstevel@tonic-gate 1001*0Sstevel@tonic-gate /* PATH */ 1002*0Sstevel@tonic-gate if (s->pw->pw_uid != 0 && (ptr = defread("PATH=")) != NULL) 1003*0Sstevel@tonic-gate child_set_env(env, envsize, "PATH", ptr); 1004*0Sstevel@tonic-gate if (s->pw->pw_uid == 0 && (ptr = defread("SUPATH=")) != NULL) 1005*0Sstevel@tonic-gate child_set_env(env, envsize, "PATH", ptr); 1006*0Sstevel@tonic-gate 1007*0Sstevel@tonic-gate /* SHELL */ 1008*0Sstevel@tonic-gate if ((ptr = defread("ALTSHELL=")) != NULL) { 1009*0Sstevel@tonic-gate if (strcasecmp("YES", ptr) == 0) 1010*0Sstevel@tonic-gate child_set_env(env, envsize, "SHELL", shell); 1011*0Sstevel@tonic-gate else 1012*0Sstevel@tonic-gate child_set_env(env, envsize, "SHELL", ""); 1013*0Sstevel@tonic-gate } 1014*0Sstevel@tonic-gate 1015*0Sstevel@tonic-gate /* UMASK */ 1016*0Sstevel@tonic-gate if ((ptr = defread("UMASK=")) != NULL && 1017*0Sstevel@tonic-gate sscanf(ptr, "%lo", &Umask) == 1 && 1018*0Sstevel@tonic-gate Umask <= (mode_t)0777) 1019*0Sstevel@tonic-gate (void) umask(Umask); 1020*0Sstevel@tonic-gate else 1021*0Sstevel@tonic-gate (void) umask(022); 1022*0Sstevel@tonic-gate 1023*0Sstevel@tonic-gate /* ULIMIT */ 1024*0Sstevel@tonic-gate if ((ptr = defread("ULIMIT=")) != NULL && atol(ptr) > 0L && 1025*0Sstevel@tonic-gate ulimit(UL_SETFSIZE, atol(ptr)) < 0L) 1026*0Sstevel@tonic-gate error("Could not set ULIMIT to %ld from %s\n", atol(ptr), 1027*0Sstevel@tonic-gate _PATH_DEFAULT_LOGIN); 1028*0Sstevel@tonic-gate 1029*0Sstevel@tonic-gate (void) defopen(NULL); 1030*0Sstevel@tonic-gate } 1031*0Sstevel@tonic-gate #endif /* HAVE_DEFOPEN */ 1032*0Sstevel@tonic-gate 1033*0Sstevel@tonic-gate static char ** 1034*0Sstevel@tonic-gate do_setup_env(Session *s, const char *shell) 1035*0Sstevel@tonic-gate { 1036*0Sstevel@tonic-gate char buf[256]; 1037*0Sstevel@tonic-gate u_int i, envsize; 1038*0Sstevel@tonic-gate char **env; 1039*0Sstevel@tonic-gate struct passwd *pw = s->pw; 1040*0Sstevel@tonic-gate 1041*0Sstevel@tonic-gate /* Initialize the environment. */ 1042*0Sstevel@tonic-gate envsize = 100; 1043*0Sstevel@tonic-gate env = xmalloc(envsize * sizeof(char *)); 1044*0Sstevel@tonic-gate env[0] = NULL; 1045*0Sstevel@tonic-gate 1046*0Sstevel@tonic-gate #ifdef HAVE_CYGWIN 1047*0Sstevel@tonic-gate /* 1048*0Sstevel@tonic-gate * The Windows environment contains some setting which are 1049*0Sstevel@tonic-gate * important for a running system. They must not be dropped. 1050*0Sstevel@tonic-gate */ 1051*0Sstevel@tonic-gate copy_environment(environ, &env, &envsize); 1052*0Sstevel@tonic-gate #endif 1053*0Sstevel@tonic-gate 1054*0Sstevel@tonic-gate #ifdef GSSAPI 1055*0Sstevel@tonic-gate /* Allow any GSSAPI methods that we've used to alter 1056*0Sstevel@tonic-gate * the childs environment as they see fit 1057*0Sstevel@tonic-gate */ 1058*0Sstevel@tonic-gate ssh_gssapi_do_child(xxx_gssctxt, &env,&envsize); 1059*0Sstevel@tonic-gate #endif 1060*0Sstevel@tonic-gate 1061*0Sstevel@tonic-gate if (!options.use_login) { 1062*0Sstevel@tonic-gate /* Set basic environment. */ 1063*0Sstevel@tonic-gate child_set_env(&env, &envsize, "USER", pw->pw_name); 1064*0Sstevel@tonic-gate child_set_env(&env, &envsize, "LOGNAME", pw->pw_name); 1065*0Sstevel@tonic-gate child_set_env(&env, &envsize, "HOME", pw->pw_dir); 1066*0Sstevel@tonic-gate #ifdef HAVE_LOGIN_CAP 1067*0Sstevel@tonic-gate if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETPATH) < 0) 1068*0Sstevel@tonic-gate child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); 1069*0Sstevel@tonic-gate else 1070*0Sstevel@tonic-gate child_set_env(&env, &envsize, "PATH", getenv("PATH")); 1071*0Sstevel@tonic-gate #else /* HAVE_LOGIN_CAP */ 1072*0Sstevel@tonic-gate # ifndef HAVE_CYGWIN 1073*0Sstevel@tonic-gate /* 1074*0Sstevel@tonic-gate * There's no standard path on Windows. The path contains 1075*0Sstevel@tonic-gate * important components pointing to the system directories, 1076*0Sstevel@tonic-gate * needed for loading shared libraries. So the path better 1077*0Sstevel@tonic-gate * remains intact here. 1078*0Sstevel@tonic-gate */ 1079*0Sstevel@tonic-gate # ifdef SUPERUSER_PATH 1080*0Sstevel@tonic-gate child_set_env(&env, &envsize, "PATH", 1081*0Sstevel@tonic-gate s->pw->pw_uid == 0 ? SUPERUSER_PATH : _PATH_STDPATH); 1082*0Sstevel@tonic-gate # else 1083*0Sstevel@tonic-gate child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); 1084*0Sstevel@tonic-gate # endif /* SUPERUSER_PATH */ 1085*0Sstevel@tonic-gate # endif /* HAVE_CYGWIN */ 1086*0Sstevel@tonic-gate #endif /* HAVE_LOGIN_CAP */ 1087*0Sstevel@tonic-gate 1088*0Sstevel@tonic-gate snprintf(buf, sizeof buf, "%.200s/%.50s", 1089*0Sstevel@tonic-gate _PATH_MAILDIR, pw->pw_name); 1090*0Sstevel@tonic-gate child_set_env(&env, &envsize, "MAIL", buf); 1091*0Sstevel@tonic-gate 1092*0Sstevel@tonic-gate /* Normal systems set SHELL by default. */ 1093*0Sstevel@tonic-gate child_set_env(&env, &envsize, "SHELL", shell); 1094*0Sstevel@tonic-gate 1095*0Sstevel@tonic-gate #ifdef HAVE_DEFOPEN 1096*0Sstevel@tonic-gate deflt_do_setup_env(s, shell, &env, &envsize); 1097*0Sstevel@tonic-gate #endif /* HAVE_DEFOPEN */ 1098*0Sstevel@tonic-gate } 1099*0Sstevel@tonic-gate 1100*0Sstevel@tonic-gate #define PASS_ENV(x) \ 1101*0Sstevel@tonic-gate if (getenv(x)) \ 1102*0Sstevel@tonic-gate child_set_env(&env, &envsize, x, getenv(x)); 1103*0Sstevel@tonic-gate 1104*0Sstevel@tonic-gate if (getenv("TZ")) 1105*0Sstevel@tonic-gate child_set_env(&env, &envsize, "TZ", getenv("TZ")); 1106*0Sstevel@tonic-gate 1107*0Sstevel@tonic-gate PASS_ENV("LANG") 1108*0Sstevel@tonic-gate PASS_ENV("LC_ALL") 1109*0Sstevel@tonic-gate PASS_ENV("LC_CTYPE") 1110*0Sstevel@tonic-gate PASS_ENV("LC_COLLATE") 1111*0Sstevel@tonic-gate PASS_ENV("LC_CTIME") 1112*0Sstevel@tonic-gate PASS_ENV("LC_NUMERIC") 1113*0Sstevel@tonic-gate PASS_ENV("LC_MONETARY") 1114*0Sstevel@tonic-gate PASS_ENV("LC_MESSAGES") 1115*0Sstevel@tonic-gate 1116*0Sstevel@tonic-gate #undef PASS_ENV 1117*0Sstevel@tonic-gate 1118*0Sstevel@tonic-gate if (s->env != NULL) 1119*0Sstevel@tonic-gate copy_environment(s->env, &env, &envsize); 1120*0Sstevel@tonic-gate 1121*0Sstevel@tonic-gate /* Set custom environment options from RSA authentication. */ 1122*0Sstevel@tonic-gate if (!options.use_login) { 1123*0Sstevel@tonic-gate while (custom_environment) { 1124*0Sstevel@tonic-gate struct envstring *ce = custom_environment; 1125*0Sstevel@tonic-gate char *str = ce->s; 1126*0Sstevel@tonic-gate 1127*0Sstevel@tonic-gate for (i = 0; str[i] != '=' && str[i]; i++) 1128*0Sstevel@tonic-gate ; 1129*0Sstevel@tonic-gate if (str[i] == '=') { 1130*0Sstevel@tonic-gate str[i] = 0; 1131*0Sstevel@tonic-gate child_set_env(&env, &envsize, str, str + i + 1); 1132*0Sstevel@tonic-gate } 1133*0Sstevel@tonic-gate custom_environment = ce->next; 1134*0Sstevel@tonic-gate xfree(ce->s); 1135*0Sstevel@tonic-gate xfree(ce); 1136*0Sstevel@tonic-gate } 1137*0Sstevel@tonic-gate } 1138*0Sstevel@tonic-gate 1139*0Sstevel@tonic-gate /* SSH_CLIENT deprecated */ 1140*0Sstevel@tonic-gate snprintf(buf, sizeof buf, "%.50s %d %d", 1141*0Sstevel@tonic-gate get_remote_ipaddr(), get_remote_port(), get_local_port()); 1142*0Sstevel@tonic-gate child_set_env(&env, &envsize, "SSH_CLIENT", buf); 1143*0Sstevel@tonic-gate 1144*0Sstevel@tonic-gate snprintf(buf, sizeof buf, "%.50s %d %.50s %d", 1145*0Sstevel@tonic-gate get_remote_ipaddr(), get_remote_port(), 1146*0Sstevel@tonic-gate get_local_ipaddr(packet_get_connection_in()), get_local_port()); 1147*0Sstevel@tonic-gate child_set_env(&env, &envsize, "SSH_CONNECTION", buf); 1148*0Sstevel@tonic-gate 1149*0Sstevel@tonic-gate if (s->ttyfd != -1) 1150*0Sstevel@tonic-gate child_set_env(&env, &envsize, "SSH_TTY", s->tty); 1151*0Sstevel@tonic-gate if (s->term) 1152*0Sstevel@tonic-gate child_set_env(&env, &envsize, "TERM", s->term); 1153*0Sstevel@tonic-gate if (s->display) 1154*0Sstevel@tonic-gate child_set_env(&env, &envsize, "DISPLAY", s->display); 1155*0Sstevel@tonic-gate if (original_command) 1156*0Sstevel@tonic-gate child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND", 1157*0Sstevel@tonic-gate original_command); 1158*0Sstevel@tonic-gate 1159*0Sstevel@tonic-gate #ifdef _UNICOS 1160*0Sstevel@tonic-gate if (cray_tmpdir[0] != '\0') 1161*0Sstevel@tonic-gate child_set_env(&env, &envsize, "TMPDIR", cray_tmpdir); 1162*0Sstevel@tonic-gate #endif /* _UNICOS */ 1163*0Sstevel@tonic-gate 1164*0Sstevel@tonic-gate #ifdef _AIX 1165*0Sstevel@tonic-gate { 1166*0Sstevel@tonic-gate char *cp; 1167*0Sstevel@tonic-gate 1168*0Sstevel@tonic-gate if ((cp = getenv("AUTHSTATE")) != NULL) 1169*0Sstevel@tonic-gate child_set_env(&env, &envsize, "AUTHSTATE", cp); 1170*0Sstevel@tonic-gate if ((cp = getenv("KRB5CCNAME")) != NULL) 1171*0Sstevel@tonic-gate child_set_env(&env, &envsize, "KRB5CCNAME", cp); 1172*0Sstevel@tonic-gate read_environment_file(&env, &envsize, "/etc/environment"); 1173*0Sstevel@tonic-gate } 1174*0Sstevel@tonic-gate #endif 1175*0Sstevel@tonic-gate #ifdef KRB4 1176*0Sstevel@tonic-gate if (s->authctxt->krb4_ticket_file) 1177*0Sstevel@tonic-gate child_set_env(&env, &envsize, "KRBTKFILE", 1178*0Sstevel@tonic-gate s->authctxt->krb4_ticket_file); 1179*0Sstevel@tonic-gate #endif 1180*0Sstevel@tonic-gate #ifdef KRB5 1181*0Sstevel@tonic-gate if (s->authctxt->krb5_ticket_file) 1182*0Sstevel@tonic-gate child_set_env(&env, &envsize, "KRB5CCNAME", 1183*0Sstevel@tonic-gate s->authctxt->krb5_ticket_file); 1184*0Sstevel@tonic-gate #endif 1185*0Sstevel@tonic-gate #ifdef USE_PAM 1186*0Sstevel@tonic-gate /* 1187*0Sstevel@tonic-gate * Pull in any environment variables that may have 1188*0Sstevel@tonic-gate * been set by PAM. 1189*0Sstevel@tonic-gate */ 1190*0Sstevel@tonic-gate { 1191*0Sstevel@tonic-gate char **p; 1192*0Sstevel@tonic-gate 1193*0Sstevel@tonic-gate p = fetch_pam_environment(s->authctxt); 1194*0Sstevel@tonic-gate copy_environment(p, &env, &envsize); 1195*0Sstevel@tonic-gate free_pam_environment(p); 1196*0Sstevel@tonic-gate } 1197*0Sstevel@tonic-gate #endif /* USE_PAM */ 1198*0Sstevel@tonic-gate 1199*0Sstevel@tonic-gate if (auth_sock_name != NULL) 1200*0Sstevel@tonic-gate child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, 1201*0Sstevel@tonic-gate auth_sock_name); 1202*0Sstevel@tonic-gate 1203*0Sstevel@tonic-gate /* read $HOME/.ssh/environment. */ 1204*0Sstevel@tonic-gate if (options.permit_user_env && !options.use_login) { 1205*0Sstevel@tonic-gate snprintf(buf, sizeof buf, "%.200s/.ssh/environment", 1206*0Sstevel@tonic-gate strcmp(pw->pw_dir, "/") ? pw->pw_dir : ""); 1207*0Sstevel@tonic-gate read_environment_file(&env, &envsize, buf); 1208*0Sstevel@tonic-gate } 1209*0Sstevel@tonic-gate if (debug_flag) { 1210*0Sstevel@tonic-gate /* dump the environment */ 1211*0Sstevel@tonic-gate fprintf(stderr, gettext("Environment:\n")); 1212*0Sstevel@tonic-gate for (i = 0; env[i]; i++) 1213*0Sstevel@tonic-gate fprintf(stderr, " %.200s\n", env[i]); 1214*0Sstevel@tonic-gate } 1215*0Sstevel@tonic-gate return env; 1216*0Sstevel@tonic-gate } 1217*0Sstevel@tonic-gate 1218*0Sstevel@tonic-gate /* 1219*0Sstevel@tonic-gate * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found 1220*0Sstevel@tonic-gate * first in this order). 1221*0Sstevel@tonic-gate */ 1222*0Sstevel@tonic-gate static void 1223*0Sstevel@tonic-gate do_rc_files(Session *s, const char *shell) 1224*0Sstevel@tonic-gate { 1225*0Sstevel@tonic-gate FILE *f = NULL; 1226*0Sstevel@tonic-gate char cmd[1024]; 1227*0Sstevel@tonic-gate int do_xauth; 1228*0Sstevel@tonic-gate struct stat st; 1229*0Sstevel@tonic-gate 1230*0Sstevel@tonic-gate do_xauth = 1231*0Sstevel@tonic-gate s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL; 1232*0Sstevel@tonic-gate 1233*0Sstevel@tonic-gate /* ignore _PATH_SSH_USER_RC for subsystems */ 1234*0Sstevel@tonic-gate if (!s->is_subsystem && (stat(_PATH_SSH_USER_RC, &st) >= 0)) { 1235*0Sstevel@tonic-gate snprintf(cmd, sizeof cmd, "%s -c '%s %s'", 1236*0Sstevel@tonic-gate shell, _PATH_BSHELL, _PATH_SSH_USER_RC); 1237*0Sstevel@tonic-gate if (debug_flag) 1238*0Sstevel@tonic-gate fprintf(stderr, "Running %s\n", cmd); 1239*0Sstevel@tonic-gate f = popen(cmd, "w"); 1240*0Sstevel@tonic-gate if (f) { 1241*0Sstevel@tonic-gate if (do_xauth) 1242*0Sstevel@tonic-gate fprintf(f, "%s %s\n", s->auth_proto, 1243*0Sstevel@tonic-gate s->auth_data); 1244*0Sstevel@tonic-gate pclose(f); 1245*0Sstevel@tonic-gate } else 1246*0Sstevel@tonic-gate fprintf(stderr, "Could not run %s\n", 1247*0Sstevel@tonic-gate _PATH_SSH_USER_RC); 1248*0Sstevel@tonic-gate } else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) { 1249*0Sstevel@tonic-gate if (debug_flag) 1250*0Sstevel@tonic-gate fprintf(stderr, "Running %s %s\n", _PATH_BSHELL, 1251*0Sstevel@tonic-gate _PATH_SSH_SYSTEM_RC); 1252*0Sstevel@tonic-gate f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w"); 1253*0Sstevel@tonic-gate if (f) { 1254*0Sstevel@tonic-gate if (do_xauth) 1255*0Sstevel@tonic-gate fprintf(f, "%s %s\n", s->auth_proto, 1256*0Sstevel@tonic-gate s->auth_data); 1257*0Sstevel@tonic-gate pclose(f); 1258*0Sstevel@tonic-gate } else 1259*0Sstevel@tonic-gate fprintf(stderr, "Could not run %s\n", 1260*0Sstevel@tonic-gate _PATH_SSH_SYSTEM_RC); 1261*0Sstevel@tonic-gate } else if (do_xauth && options.xauth_location != NULL) { 1262*0Sstevel@tonic-gate /* Add authority data to .Xauthority if appropriate. */ 1263*0Sstevel@tonic-gate if (debug_flag) { 1264*0Sstevel@tonic-gate fprintf(stderr, 1265*0Sstevel@tonic-gate "Running %.500s add " 1266*0Sstevel@tonic-gate "%.100s %.100s %.100s\n", 1267*0Sstevel@tonic-gate options.xauth_location, s->auth_display, 1268*0Sstevel@tonic-gate s->auth_proto, s->auth_data); 1269*0Sstevel@tonic-gate } 1270*0Sstevel@tonic-gate snprintf(cmd, sizeof cmd, "%s -q -", 1271*0Sstevel@tonic-gate options.xauth_location); 1272*0Sstevel@tonic-gate f = popen(cmd, "w"); 1273*0Sstevel@tonic-gate if (f) { 1274*0Sstevel@tonic-gate fprintf(f, "add %s %s %s\n", 1275*0Sstevel@tonic-gate s->auth_display, s->auth_proto, 1276*0Sstevel@tonic-gate s->auth_data); 1277*0Sstevel@tonic-gate pclose(f); 1278*0Sstevel@tonic-gate } else { 1279*0Sstevel@tonic-gate fprintf(stderr, "Could not run %s\n", 1280*0Sstevel@tonic-gate cmd); 1281*0Sstevel@tonic-gate } 1282*0Sstevel@tonic-gate } 1283*0Sstevel@tonic-gate } 1284*0Sstevel@tonic-gate 1285*0Sstevel@tonic-gate static void 1286*0Sstevel@tonic-gate do_nologin(struct passwd *pw) 1287*0Sstevel@tonic-gate { 1288*0Sstevel@tonic-gate FILE *f = NULL; 1289*0Sstevel@tonic-gate char buf[1024]; 1290*0Sstevel@tonic-gate 1291*0Sstevel@tonic-gate #ifdef HAVE_LOGIN_CAP 1292*0Sstevel@tonic-gate if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid) 1293*0Sstevel@tonic-gate f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN, 1294*0Sstevel@tonic-gate _PATH_NOLOGIN), "r"); 1295*0Sstevel@tonic-gate #else 1296*0Sstevel@tonic-gate if (pw->pw_uid) 1297*0Sstevel@tonic-gate f = fopen(_PATH_NOLOGIN, "r"); 1298*0Sstevel@tonic-gate #endif 1299*0Sstevel@tonic-gate if (f) { 1300*0Sstevel@tonic-gate /* /etc/nologin exists. Print its contents and exit. */ 1301*0Sstevel@tonic-gate log("User %.100s not allowed because %s exists", 1302*0Sstevel@tonic-gate pw->pw_name, _PATH_NOLOGIN); 1303*0Sstevel@tonic-gate while (fgets(buf, sizeof(buf), f)) 1304*0Sstevel@tonic-gate fputs(buf, stderr); 1305*0Sstevel@tonic-gate fclose(f); 1306*0Sstevel@tonic-gate exit(254); 1307*0Sstevel@tonic-gate } 1308*0Sstevel@tonic-gate } 1309*0Sstevel@tonic-gate 1310*0Sstevel@tonic-gate /* Set login name, uid, gid, and groups. */ 1311*0Sstevel@tonic-gate void 1312*0Sstevel@tonic-gate do_setusercontext(struct passwd *pw) 1313*0Sstevel@tonic-gate { 1314*0Sstevel@tonic-gate #ifdef HAVE_CYGWIN 1315*0Sstevel@tonic-gate if (is_winnt) { 1316*0Sstevel@tonic-gate #else /* HAVE_CYGWIN */ 1317*0Sstevel@tonic-gate if (getuid() == 0 || geteuid() == 0) { 1318*0Sstevel@tonic-gate #endif /* HAVE_CYGWIN */ 1319*0Sstevel@tonic-gate #ifdef HAVE_SETPCRED 1320*0Sstevel@tonic-gate setpcred(pw->pw_name); 1321*0Sstevel@tonic-gate #endif /* HAVE_SETPCRED */ 1322*0Sstevel@tonic-gate #ifdef HAVE_LOGIN_CAP 1323*0Sstevel@tonic-gate # ifdef __bsdi__ 1324*0Sstevel@tonic-gate setpgid(0, 0); 1325*0Sstevel@tonic-gate # endif 1326*0Sstevel@tonic-gate if (setusercontext(lc, pw, pw->pw_uid, 1327*0Sstevel@tonic-gate (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) { 1328*0Sstevel@tonic-gate perror("unable to set user context"); 1329*0Sstevel@tonic-gate exit(1); 1330*0Sstevel@tonic-gate } 1331*0Sstevel@tonic-gate #else 1332*0Sstevel@tonic-gate # if defined(HAVE_GETLUID) && defined(HAVE_SETLUID) 1333*0Sstevel@tonic-gate /* Sets login uid for accounting */ 1334*0Sstevel@tonic-gate if (getluid() == -1 && setluid(pw->pw_uid) == -1) 1335*0Sstevel@tonic-gate error("setluid: %s", strerror(errno)); 1336*0Sstevel@tonic-gate # endif /* defined(HAVE_GETLUID) && defined(HAVE_SETLUID) */ 1337*0Sstevel@tonic-gate 1338*0Sstevel@tonic-gate if (setlogin(pw->pw_name) < 0) 1339*0Sstevel@tonic-gate error("setlogin failed: %s", strerror(errno)); 1340*0Sstevel@tonic-gate if (setgid(pw->pw_gid) < 0) { 1341*0Sstevel@tonic-gate perror("setgid"); 1342*0Sstevel@tonic-gate exit(1); 1343*0Sstevel@tonic-gate } 1344*0Sstevel@tonic-gate /* Initialize the group list. */ 1345*0Sstevel@tonic-gate if (initgroups(pw->pw_name, pw->pw_gid) < 0) { 1346*0Sstevel@tonic-gate perror("initgroups"); 1347*0Sstevel@tonic-gate exit(1); 1348*0Sstevel@tonic-gate } 1349*0Sstevel@tonic-gate endgrent(); 1350*0Sstevel@tonic-gate # if 0 1351*0Sstevel@tonic-gate # ifdef USE_PAM 1352*0Sstevel@tonic-gate /* 1353*0Sstevel@tonic-gate * PAM credentials may take the form of supplementary groups. 1354*0Sstevel@tonic-gate * These will have been wiped by the above initgroups() call. 1355*0Sstevel@tonic-gate * Reestablish them here. 1356*0Sstevel@tonic-gate */ 1357*0Sstevel@tonic-gate do_pam_setcred(0); 1358*0Sstevel@tonic-gate # endif /* USE_PAM */ 1359*0Sstevel@tonic-gate # endif /* 0 */ 1360*0Sstevel@tonic-gate # if defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) 1361*0Sstevel@tonic-gate irix_setusercontext(pw); 1362*0Sstevel@tonic-gate # endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */ 1363*0Sstevel@tonic-gate # ifdef _AIX 1364*0Sstevel@tonic-gate aix_usrinfo(pw); 1365*0Sstevel@tonic-gate # endif /* _AIX */ 1366*0Sstevel@tonic-gate /* Permanently switch to the desired uid. */ 1367*0Sstevel@tonic-gate permanently_set_uid(pw); 1368*0Sstevel@tonic-gate #endif 1369*0Sstevel@tonic-gate } 1370*0Sstevel@tonic-gate if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) 1371*0Sstevel@tonic-gate fatal("Failed to set uids to %u.", (u_int) pw->pw_uid); 1372*0Sstevel@tonic-gate } 1373*0Sstevel@tonic-gate 1374*0Sstevel@tonic-gate static void 1375*0Sstevel@tonic-gate launch_login(struct passwd *pw, const char *hostname) 1376*0Sstevel@tonic-gate { 1377*0Sstevel@tonic-gate /* Launch login(1). */ 1378*0Sstevel@tonic-gate 1379*0Sstevel@tonic-gate execl(LOGIN_PROGRAM, "login", "-h", hostname, 1380*0Sstevel@tonic-gate #ifdef xxxLOGIN_NEEDS_TERM 1381*0Sstevel@tonic-gate (s->term ? s->term : "unknown"), 1382*0Sstevel@tonic-gate #endif /* LOGIN_NEEDS_TERM */ 1383*0Sstevel@tonic-gate #ifdef LOGIN_NO_ENDOPT 1384*0Sstevel@tonic-gate "-p", "-f", pw->pw_name, (char *)NULL); 1385*0Sstevel@tonic-gate #else 1386*0Sstevel@tonic-gate "-p", "-f", "--", pw->pw_name, (char *)NULL); 1387*0Sstevel@tonic-gate #endif 1388*0Sstevel@tonic-gate 1389*0Sstevel@tonic-gate /* Login couldn't be executed, die. */ 1390*0Sstevel@tonic-gate 1391*0Sstevel@tonic-gate perror("login"); 1392*0Sstevel@tonic-gate exit(1); 1393*0Sstevel@tonic-gate } 1394*0Sstevel@tonic-gate 1395*0Sstevel@tonic-gate /* 1396*0Sstevel@tonic-gate * Performs common processing for the child, such as setting up the 1397*0Sstevel@tonic-gate * environment, closing extra file descriptors, setting the user and group 1398*0Sstevel@tonic-gate * ids, and executing the command or shell. 1399*0Sstevel@tonic-gate */ 1400*0Sstevel@tonic-gate void 1401*0Sstevel@tonic-gate do_child(Session *s, const char *command) 1402*0Sstevel@tonic-gate { 1403*0Sstevel@tonic-gate extern char **environ; 1404*0Sstevel@tonic-gate char **env; 1405*0Sstevel@tonic-gate char *argv[10]; 1406*0Sstevel@tonic-gate const char *shell, *shell0, *hostname = NULL; 1407*0Sstevel@tonic-gate struct passwd *pw = s->pw; 1408*0Sstevel@tonic-gate 1409*0Sstevel@tonic-gate /* remove hostkey from the child's memory */ 1410*0Sstevel@tonic-gate destroy_sensitive_data(); 1411*0Sstevel@tonic-gate 1412*0Sstevel@tonic-gate /* login(1) is only called if we execute the login shell */ 1413*0Sstevel@tonic-gate if (options.use_login && command != NULL) 1414*0Sstevel@tonic-gate options.use_login = 0; 1415*0Sstevel@tonic-gate 1416*0Sstevel@tonic-gate #ifdef _UNICOS 1417*0Sstevel@tonic-gate cray_setup(pw->pw_uid, pw->pw_name, command); 1418*0Sstevel@tonic-gate #endif /* _UNICOS */ 1419*0Sstevel@tonic-gate 1420*0Sstevel@tonic-gate /* 1421*0Sstevel@tonic-gate * Login(1) does this as well, and it needs uid 0 for the "-h" 1422*0Sstevel@tonic-gate * switch, so we let login(1) to this for us. 1423*0Sstevel@tonic-gate */ 1424*0Sstevel@tonic-gate if (!options.use_login) { 1425*0Sstevel@tonic-gate #ifdef HAVE_OSF_SIA 1426*0Sstevel@tonic-gate session_setup_sia(pw->pw_name, s->ttyfd == -1 ? NULL : s->tty); 1427*0Sstevel@tonic-gate if (!check_quietlogin(s, command)) 1428*0Sstevel@tonic-gate do_motd(); 1429*0Sstevel@tonic-gate #else /* HAVE_OSF_SIA */ 1430*0Sstevel@tonic-gate do_nologin(pw); 1431*0Sstevel@tonic-gate do_setusercontext(pw); 1432*0Sstevel@tonic-gate #endif /* HAVE_OSF_SIA */ 1433*0Sstevel@tonic-gate } 1434*0Sstevel@tonic-gate 1435*0Sstevel@tonic-gate /* 1436*0Sstevel@tonic-gate * Get the shell from the password data. An empty shell field is 1437*0Sstevel@tonic-gate * legal, and means /bin/sh. 1438*0Sstevel@tonic-gate */ 1439*0Sstevel@tonic-gate shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; 1440*0Sstevel@tonic-gate #ifdef HAVE_LOGIN_CAP 1441*0Sstevel@tonic-gate shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell); 1442*0Sstevel@tonic-gate #endif 1443*0Sstevel@tonic-gate 1444*0Sstevel@tonic-gate env = do_setup_env(s, shell); 1445*0Sstevel@tonic-gate 1446*0Sstevel@tonic-gate /* we have to stash the hostname before we close our socket. */ 1447*0Sstevel@tonic-gate if (options.use_login) 1448*0Sstevel@tonic-gate hostname = get_remote_name_or_ip(utmp_len, 1449*0Sstevel@tonic-gate options.verify_reverse_mapping); 1450*0Sstevel@tonic-gate /* 1451*0Sstevel@tonic-gate * Close the connection descriptors; note that this is the child, and 1452*0Sstevel@tonic-gate * the server will still have the socket open, and it is important 1453*0Sstevel@tonic-gate * that we do not shutdown it. Note that the descriptors cannot be 1454*0Sstevel@tonic-gate * closed before building the environment, as we call 1455*0Sstevel@tonic-gate * get_remote_ipaddr there. 1456*0Sstevel@tonic-gate */ 1457*0Sstevel@tonic-gate if (packet_get_connection_in() == packet_get_connection_out()) 1458*0Sstevel@tonic-gate close(packet_get_connection_in()); 1459*0Sstevel@tonic-gate else { 1460*0Sstevel@tonic-gate close(packet_get_connection_in()); 1461*0Sstevel@tonic-gate close(packet_get_connection_out()); 1462*0Sstevel@tonic-gate } 1463*0Sstevel@tonic-gate /* 1464*0Sstevel@tonic-gate * Close all descriptors related to channels. They will still remain 1465*0Sstevel@tonic-gate * open in the parent. 1466*0Sstevel@tonic-gate */ 1467*0Sstevel@tonic-gate /* XXX better use close-on-exec? -markus */ 1468*0Sstevel@tonic-gate channel_close_all(); 1469*0Sstevel@tonic-gate 1470*0Sstevel@tonic-gate /* 1471*0Sstevel@tonic-gate * Close any extra file descriptors. Note that there may still be 1472*0Sstevel@tonic-gate * descriptors left by system functions. They will be closed later. 1473*0Sstevel@tonic-gate */ 1474*0Sstevel@tonic-gate endpwent(); 1475*0Sstevel@tonic-gate 1476*0Sstevel@tonic-gate /* 1477*0Sstevel@tonic-gate * Close any extra open file descriptors so that we don\'t have them 1478*0Sstevel@tonic-gate * hanging around in clients. Note that we want to do this after 1479*0Sstevel@tonic-gate * initgroups, because at least on Solaris 2.3 it leaves file 1480*0Sstevel@tonic-gate * descriptors open. 1481*0Sstevel@tonic-gate */ 1482*0Sstevel@tonic-gate closefrom(STDERR_FILENO + 1); 1483*0Sstevel@tonic-gate 1484*0Sstevel@tonic-gate /* 1485*0Sstevel@tonic-gate * Must take new environment into use so that .ssh/rc, 1486*0Sstevel@tonic-gate * /etc/ssh/sshrc and xauth are run in the proper environment. 1487*0Sstevel@tonic-gate */ 1488*0Sstevel@tonic-gate environ = env; 1489*0Sstevel@tonic-gate 1490*0Sstevel@tonic-gate #ifdef AFS 1491*0Sstevel@tonic-gate /* Try to get AFS tokens for the local cell. */ 1492*0Sstevel@tonic-gate if (k_hasafs()) { 1493*0Sstevel@tonic-gate char cell[64]; 1494*0Sstevel@tonic-gate 1495*0Sstevel@tonic-gate if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0) 1496*0Sstevel@tonic-gate krb_afslog(cell, 0); 1497*0Sstevel@tonic-gate 1498*0Sstevel@tonic-gate krb_afslog(0, 0); 1499*0Sstevel@tonic-gate } 1500*0Sstevel@tonic-gate #endif /* AFS */ 1501*0Sstevel@tonic-gate 1502*0Sstevel@tonic-gate /* Change current directory to the user\'s home directory. */ 1503*0Sstevel@tonic-gate if (chdir(pw->pw_dir) < 0) { 1504*0Sstevel@tonic-gate fprintf(stderr, 1505*0Sstevel@tonic-gate gettext("Could not chdir to home directory %s: %s\n"), 1506*0Sstevel@tonic-gate pw->pw_dir, strerror(errno)); 1507*0Sstevel@tonic-gate #ifdef HAVE_LOGIN_CAP 1508*0Sstevel@tonic-gate if (login_getcapbool(lc, "requirehome", 0)) 1509*0Sstevel@tonic-gate exit(1); 1510*0Sstevel@tonic-gate #endif 1511*0Sstevel@tonic-gate } 1512*0Sstevel@tonic-gate 1513*0Sstevel@tonic-gate if (!options.use_login) 1514*0Sstevel@tonic-gate do_rc_files(s, shell); 1515*0Sstevel@tonic-gate 1516*0Sstevel@tonic-gate /* restore SIGPIPE for child */ 1517*0Sstevel@tonic-gate signal(SIGPIPE, SIG_DFL); 1518*0Sstevel@tonic-gate 1519*0Sstevel@tonic-gate if (options.use_login) { 1520*0Sstevel@tonic-gate launch_login(pw, hostname); 1521*0Sstevel@tonic-gate /* NEVERREACHED */ 1522*0Sstevel@tonic-gate } 1523*0Sstevel@tonic-gate 1524*0Sstevel@tonic-gate /* Get the last component of the shell name. */ 1525*0Sstevel@tonic-gate if ((shell0 = strrchr(shell, '/')) != NULL) 1526*0Sstevel@tonic-gate shell0++; 1527*0Sstevel@tonic-gate else 1528*0Sstevel@tonic-gate shell0 = shell; 1529*0Sstevel@tonic-gate 1530*0Sstevel@tonic-gate /* 1531*0Sstevel@tonic-gate * If we have no command, execute the shell. In this case, the shell 1532*0Sstevel@tonic-gate * name to be passed in argv[0] is preceded by '-' to indicate that 1533*0Sstevel@tonic-gate * this is a login shell. 1534*0Sstevel@tonic-gate */ 1535*0Sstevel@tonic-gate if (!command) { 1536*0Sstevel@tonic-gate char argv0[256]; 1537*0Sstevel@tonic-gate 1538*0Sstevel@tonic-gate /* Start the shell. Set initial character to '-'. */ 1539*0Sstevel@tonic-gate argv0[0] = '-'; 1540*0Sstevel@tonic-gate 1541*0Sstevel@tonic-gate if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1) 1542*0Sstevel@tonic-gate >= sizeof(argv0) - 1) { 1543*0Sstevel@tonic-gate errno = EINVAL; 1544*0Sstevel@tonic-gate perror(shell); 1545*0Sstevel@tonic-gate exit(1); 1546*0Sstevel@tonic-gate } 1547*0Sstevel@tonic-gate 1548*0Sstevel@tonic-gate /* Execute the shell. */ 1549*0Sstevel@tonic-gate argv[0] = argv0; 1550*0Sstevel@tonic-gate argv[1] = NULL; 1551*0Sstevel@tonic-gate execve(shell, argv, env); 1552*0Sstevel@tonic-gate 1553*0Sstevel@tonic-gate /* Executing the shell failed. */ 1554*0Sstevel@tonic-gate perror(shell); 1555*0Sstevel@tonic-gate exit(1); 1556*0Sstevel@tonic-gate } 1557*0Sstevel@tonic-gate /* 1558*0Sstevel@tonic-gate * Execute the command using the user's shell. This uses the -c 1559*0Sstevel@tonic-gate * option to execute the command. 1560*0Sstevel@tonic-gate */ 1561*0Sstevel@tonic-gate argv[0] = (char *) shell0; 1562*0Sstevel@tonic-gate argv[1] = "-c"; 1563*0Sstevel@tonic-gate argv[2] = (char *) command; 1564*0Sstevel@tonic-gate argv[3] = NULL; 1565*0Sstevel@tonic-gate execve(shell, argv, env); 1566*0Sstevel@tonic-gate perror(shell); 1567*0Sstevel@tonic-gate exit(1); 1568*0Sstevel@tonic-gate } 1569*0Sstevel@tonic-gate 1570*0Sstevel@tonic-gate Session * 1571*0Sstevel@tonic-gate session_new(void) 1572*0Sstevel@tonic-gate { 1573*0Sstevel@tonic-gate int i; 1574*0Sstevel@tonic-gate static int did_init = 0; 1575*0Sstevel@tonic-gate if (!did_init) { 1576*0Sstevel@tonic-gate debug("session_new: init"); 1577*0Sstevel@tonic-gate for (i = 0; i < MAX_SESSIONS; i++) { 1578*0Sstevel@tonic-gate sessions[i].used = 0; 1579*0Sstevel@tonic-gate } 1580*0Sstevel@tonic-gate did_init = 1; 1581*0Sstevel@tonic-gate } 1582*0Sstevel@tonic-gate for (i = 0; i < MAX_SESSIONS; i++) { 1583*0Sstevel@tonic-gate Session *s = &sessions[i]; 1584*0Sstevel@tonic-gate if (! s->used) { 1585*0Sstevel@tonic-gate memset(s, 0, sizeof(*s)); 1586*0Sstevel@tonic-gate s->chanid = -1; 1587*0Sstevel@tonic-gate s->ptyfd = -1; 1588*0Sstevel@tonic-gate s->ttyfd = -1; 1589*0Sstevel@tonic-gate s->used = 1; 1590*0Sstevel@tonic-gate s->self = i; 1591*0Sstevel@tonic-gate s->env = NULL; 1592*0Sstevel@tonic-gate debug("session_new: session %d", i); 1593*0Sstevel@tonic-gate return s; 1594*0Sstevel@tonic-gate } 1595*0Sstevel@tonic-gate } 1596*0Sstevel@tonic-gate return NULL; 1597*0Sstevel@tonic-gate } 1598*0Sstevel@tonic-gate 1599*0Sstevel@tonic-gate static void 1600*0Sstevel@tonic-gate session_dump(void) 1601*0Sstevel@tonic-gate { 1602*0Sstevel@tonic-gate int i; 1603*0Sstevel@tonic-gate for (i = 0; i < MAX_SESSIONS; i++) { 1604*0Sstevel@tonic-gate Session *s = &sessions[i]; 1605*0Sstevel@tonic-gate debug("dump: used %d session %d %p channel %d pid %ld", 1606*0Sstevel@tonic-gate s->used, 1607*0Sstevel@tonic-gate s->self, 1608*0Sstevel@tonic-gate s, 1609*0Sstevel@tonic-gate s->chanid, 1610*0Sstevel@tonic-gate (long)s->pid); 1611*0Sstevel@tonic-gate } 1612*0Sstevel@tonic-gate } 1613*0Sstevel@tonic-gate 1614*0Sstevel@tonic-gate int 1615*0Sstevel@tonic-gate session_open(Authctxt *authctxt, int chanid) 1616*0Sstevel@tonic-gate { 1617*0Sstevel@tonic-gate Session *s = session_new(); 1618*0Sstevel@tonic-gate debug("session_open: channel %d", chanid); 1619*0Sstevel@tonic-gate if (s == NULL) { 1620*0Sstevel@tonic-gate error("no more sessions"); 1621*0Sstevel@tonic-gate return 0; 1622*0Sstevel@tonic-gate } 1623*0Sstevel@tonic-gate s->authctxt = authctxt; 1624*0Sstevel@tonic-gate s->pw = authctxt->pw; 1625*0Sstevel@tonic-gate if (s->pw == NULL) 1626*0Sstevel@tonic-gate fatal("no user for session %d", s->self); 1627*0Sstevel@tonic-gate debug("session_open: session %d: link with channel %d", s->self, chanid); 1628*0Sstevel@tonic-gate s->chanid = chanid; 1629*0Sstevel@tonic-gate return 1; 1630*0Sstevel@tonic-gate } 1631*0Sstevel@tonic-gate 1632*0Sstevel@tonic-gate #ifndef lint 1633*0Sstevel@tonic-gate Session * 1634*0Sstevel@tonic-gate session_by_tty(char *tty) 1635*0Sstevel@tonic-gate { 1636*0Sstevel@tonic-gate int i; 1637*0Sstevel@tonic-gate for (i = 0; i < MAX_SESSIONS; i++) { 1638*0Sstevel@tonic-gate Session *s = &sessions[i]; 1639*0Sstevel@tonic-gate if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) { 1640*0Sstevel@tonic-gate debug("session_by_tty: session %d tty %s", i, tty); 1641*0Sstevel@tonic-gate return s; 1642*0Sstevel@tonic-gate } 1643*0Sstevel@tonic-gate } 1644*0Sstevel@tonic-gate debug("session_by_tty: unknown tty %.100s", tty); 1645*0Sstevel@tonic-gate session_dump(); 1646*0Sstevel@tonic-gate return NULL; 1647*0Sstevel@tonic-gate } 1648*0Sstevel@tonic-gate #endif /* lint */ 1649*0Sstevel@tonic-gate 1650*0Sstevel@tonic-gate static Session * 1651*0Sstevel@tonic-gate session_by_channel(int id) 1652*0Sstevel@tonic-gate { 1653*0Sstevel@tonic-gate int i; 1654*0Sstevel@tonic-gate for (i = 0; i < MAX_SESSIONS; i++) { 1655*0Sstevel@tonic-gate Session *s = &sessions[i]; 1656*0Sstevel@tonic-gate if (s->used && s->chanid == id) { 1657*0Sstevel@tonic-gate debug("session_by_channel: session %d channel %d", i, id); 1658*0Sstevel@tonic-gate return s; 1659*0Sstevel@tonic-gate } 1660*0Sstevel@tonic-gate } 1661*0Sstevel@tonic-gate debug("session_by_channel: unknown channel %d", id); 1662*0Sstevel@tonic-gate session_dump(); 1663*0Sstevel@tonic-gate return NULL; 1664*0Sstevel@tonic-gate } 1665*0Sstevel@tonic-gate 1666*0Sstevel@tonic-gate static Session * 1667*0Sstevel@tonic-gate session_by_pid(pid_t pid) 1668*0Sstevel@tonic-gate { 1669*0Sstevel@tonic-gate int i; 1670*0Sstevel@tonic-gate debug("session_by_pid: pid %ld", (long)pid); 1671*0Sstevel@tonic-gate for (i = 0; i < MAX_SESSIONS; i++) { 1672*0Sstevel@tonic-gate Session *s = &sessions[i]; 1673*0Sstevel@tonic-gate if (s->used && s->pid == pid) 1674*0Sstevel@tonic-gate return s; 1675*0Sstevel@tonic-gate } 1676*0Sstevel@tonic-gate error("session_by_pid: unknown pid %ld", (long)pid); 1677*0Sstevel@tonic-gate session_dump(); 1678*0Sstevel@tonic-gate return NULL; 1679*0Sstevel@tonic-gate } 1680*0Sstevel@tonic-gate 1681*0Sstevel@tonic-gate static int 1682*0Sstevel@tonic-gate session_window_change_req(Session *s) 1683*0Sstevel@tonic-gate { 1684*0Sstevel@tonic-gate s->col = packet_get_int(); 1685*0Sstevel@tonic-gate s->row = packet_get_int(); 1686*0Sstevel@tonic-gate s->xpixel = packet_get_int(); 1687*0Sstevel@tonic-gate s->ypixel = packet_get_int(); 1688*0Sstevel@tonic-gate packet_check_eom(); 1689*0Sstevel@tonic-gate pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); 1690*0Sstevel@tonic-gate return 1; 1691*0Sstevel@tonic-gate } 1692*0Sstevel@tonic-gate 1693*0Sstevel@tonic-gate static int 1694*0Sstevel@tonic-gate session_pty_req(Session *s) 1695*0Sstevel@tonic-gate { 1696*0Sstevel@tonic-gate u_int len; 1697*0Sstevel@tonic-gate int n_bytes; 1698*0Sstevel@tonic-gate 1699*0Sstevel@tonic-gate if (no_pty_flag) { 1700*0Sstevel@tonic-gate debug("Allocating a pty not permitted for this authentication."); 1701*0Sstevel@tonic-gate return 0; 1702*0Sstevel@tonic-gate } 1703*0Sstevel@tonic-gate if (s->ttyfd != -1) { 1704*0Sstevel@tonic-gate packet_disconnect("Protocol error: you already have a pty."); 1705*0Sstevel@tonic-gate return 0; 1706*0Sstevel@tonic-gate } 1707*0Sstevel@tonic-gate /* Get the time and hostname when the user last logged in. */ 1708*0Sstevel@tonic-gate if (options.print_lastlog) { 1709*0Sstevel@tonic-gate s->hostname[0] = '\0'; 1710*0Sstevel@tonic-gate s->last_login_time = get_last_login_time(s->pw->pw_uid, 1711*0Sstevel@tonic-gate s->pw->pw_name, s->hostname, sizeof(s->hostname)); 1712*0Sstevel@tonic-gate 1713*0Sstevel@tonic-gate /* 1714*0Sstevel@tonic-gate * PAM may update the last login date. 1715*0Sstevel@tonic-gate * 1716*0Sstevel@tonic-gate * Ideally PAM would also show the last login date as a 1717*0Sstevel@tonic-gate * PAM_TEXT_INFO conversation message, and then we could just 1718*0Sstevel@tonic-gate * always force the use of keyboard-interactive just so we can 1719*0Sstevel@tonic-gate * pass any such PAM prompts and messages from the account and 1720*0Sstevel@tonic-gate * session stacks, but skip pam_authenticate() if other userauth 1721*0Sstevel@tonic-gate * has succeeded and the user's password isn't expired. 1722*0Sstevel@tonic-gate * 1723*0Sstevel@tonic-gate * Unfortunately this depends on support for keyboard- 1724*0Sstevel@tonic-gate * interactive in the client, and support for lastlog messages 1725*0Sstevel@tonic-gate * in some PAM module. 1726*0Sstevel@tonic-gate * 1727*0Sstevel@tonic-gate * As it is Solaris updates the lastlog in PAM, but does 1728*0Sstevel@tonic-gate * not show the lastlog date in PAM. If and when this state of 1729*0Sstevel@tonic-gate * affairs changes this hack can be reconsidered, and, maybe, 1730*0Sstevel@tonic-gate * removed. 1731*0Sstevel@tonic-gate * 1732*0Sstevel@tonic-gate * So we're stuck with a crude hack: get the lastlog 1733*0Sstevel@tonic-gate * time before calling pam_open_session() and store it 1734*0Sstevel@tonic-gate * in the Authctxt and then use it here once. After 1735*0Sstevel@tonic-gate * that, if the client opens any more pty sessions we'll 1736*0Sstevel@tonic-gate * show the last lastlog entry since userauth. 1737*0Sstevel@tonic-gate */ 1738*0Sstevel@tonic-gate if (s->authctxt != NULL && s->authctxt->last_login_time > 0) { 1739*0Sstevel@tonic-gate s->last_login_time = s->authctxt->last_login_time; 1740*0Sstevel@tonic-gate (void) strlcpy(s->hostname, 1741*0Sstevel@tonic-gate s->authctxt->last_login_host, 1742*0Sstevel@tonic-gate sizeof(s->hostname)); 1743*0Sstevel@tonic-gate s->authctxt->last_login_time = 0; 1744*0Sstevel@tonic-gate s->authctxt->last_login_host[0] = '\0'; 1745*0Sstevel@tonic-gate } 1746*0Sstevel@tonic-gate } 1747*0Sstevel@tonic-gate 1748*0Sstevel@tonic-gate s->term = packet_get_string(&len); 1749*0Sstevel@tonic-gate 1750*0Sstevel@tonic-gate if (compat20) { 1751*0Sstevel@tonic-gate s->col = packet_get_int(); 1752*0Sstevel@tonic-gate s->row = packet_get_int(); 1753*0Sstevel@tonic-gate } else { 1754*0Sstevel@tonic-gate s->row = packet_get_int(); 1755*0Sstevel@tonic-gate s->col = packet_get_int(); 1756*0Sstevel@tonic-gate } 1757*0Sstevel@tonic-gate s->xpixel = packet_get_int(); 1758*0Sstevel@tonic-gate s->ypixel = packet_get_int(); 1759*0Sstevel@tonic-gate 1760*0Sstevel@tonic-gate if (strcmp(s->term, "") == 0) { 1761*0Sstevel@tonic-gate xfree(s->term); 1762*0Sstevel@tonic-gate s->term = NULL; 1763*0Sstevel@tonic-gate } 1764*0Sstevel@tonic-gate 1765*0Sstevel@tonic-gate /* Allocate a pty and open it. */ 1766*0Sstevel@tonic-gate debug("Allocating pty."); 1767*0Sstevel@tonic-gate if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)))) { 1768*0Sstevel@tonic-gate if (s->term) 1769*0Sstevel@tonic-gate xfree(s->term); 1770*0Sstevel@tonic-gate s->term = NULL; 1771*0Sstevel@tonic-gate s->ptyfd = -1; 1772*0Sstevel@tonic-gate s->ttyfd = -1; 1773*0Sstevel@tonic-gate error("session_pty_req: session %d alloc failed", s->self); 1774*0Sstevel@tonic-gate return 0; 1775*0Sstevel@tonic-gate } 1776*0Sstevel@tonic-gate debug("session_pty_req: session %d alloc %s", s->self, s->tty); 1777*0Sstevel@tonic-gate 1778*0Sstevel@tonic-gate /* for SSH1 the tty modes length is not given */ 1779*0Sstevel@tonic-gate if (!compat20) 1780*0Sstevel@tonic-gate n_bytes = packet_remaining(); 1781*0Sstevel@tonic-gate tty_parse_modes(s->ttyfd, &n_bytes); 1782*0Sstevel@tonic-gate 1783*0Sstevel@tonic-gate /* 1784*0Sstevel@tonic-gate * Add a cleanup function to clear the utmp entry and record logout 1785*0Sstevel@tonic-gate * time in case we call fatal() (e.g., the connection gets closed). 1786*0Sstevel@tonic-gate */ 1787*0Sstevel@tonic-gate fatal_add_cleanup(session_pty_cleanup, (void *)s); 1788*0Sstevel@tonic-gate if (!use_privsep) 1789*0Sstevel@tonic-gate pty_setowner(s->pw, s->tty); 1790*0Sstevel@tonic-gate 1791*0Sstevel@tonic-gate /* Set window size from the packet. */ 1792*0Sstevel@tonic-gate pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); 1793*0Sstevel@tonic-gate 1794*0Sstevel@tonic-gate packet_check_eom(); 1795*0Sstevel@tonic-gate session_proctitle(s); 1796*0Sstevel@tonic-gate return 1; 1797*0Sstevel@tonic-gate } 1798*0Sstevel@tonic-gate 1799*0Sstevel@tonic-gate static int 1800*0Sstevel@tonic-gate session_subsystem_req(Session *s) 1801*0Sstevel@tonic-gate { 1802*0Sstevel@tonic-gate struct stat st; 1803*0Sstevel@tonic-gate u_int len; 1804*0Sstevel@tonic-gate int success = 0; 1805*0Sstevel@tonic-gate char *cmd, *subsys = packet_get_string(&len); 1806*0Sstevel@tonic-gate int i; 1807*0Sstevel@tonic-gate 1808*0Sstevel@tonic-gate packet_check_eom(); 1809*0Sstevel@tonic-gate log("subsystem request for %.100s", subsys); 1810*0Sstevel@tonic-gate 1811*0Sstevel@tonic-gate for (i = 0; i < options.num_subsystems; i++) { 1812*0Sstevel@tonic-gate if (strcmp(subsys, options.subsystem_name[i]) == 0) { 1813*0Sstevel@tonic-gate cmd = options.subsystem_command[i]; 1814*0Sstevel@tonic-gate if (stat(cmd, &st) < 0) { 1815*0Sstevel@tonic-gate error("subsystem: cannot stat %s: %s", cmd, 1816*0Sstevel@tonic-gate strerror(errno)); 1817*0Sstevel@tonic-gate break; 1818*0Sstevel@tonic-gate } 1819*0Sstevel@tonic-gate debug("subsystem: exec() %s", cmd); 1820*0Sstevel@tonic-gate s->is_subsystem = 1; 1821*0Sstevel@tonic-gate do_exec(s, cmd); 1822*0Sstevel@tonic-gate success = 1; 1823*0Sstevel@tonic-gate break; 1824*0Sstevel@tonic-gate } 1825*0Sstevel@tonic-gate } 1826*0Sstevel@tonic-gate 1827*0Sstevel@tonic-gate if (!success) 1828*0Sstevel@tonic-gate log("subsystem request for %.100s failed, subsystem not found", 1829*0Sstevel@tonic-gate subsys); 1830*0Sstevel@tonic-gate 1831*0Sstevel@tonic-gate xfree(subsys); 1832*0Sstevel@tonic-gate return success; 1833*0Sstevel@tonic-gate } 1834*0Sstevel@tonic-gate 1835*0Sstevel@tonic-gate static int 1836*0Sstevel@tonic-gate session_x11_req(Session *s) 1837*0Sstevel@tonic-gate { 1838*0Sstevel@tonic-gate int success; 1839*0Sstevel@tonic-gate 1840*0Sstevel@tonic-gate s->single_connection = packet_get_char(); 1841*0Sstevel@tonic-gate s->auth_proto = packet_get_string(NULL); 1842*0Sstevel@tonic-gate s->auth_data = packet_get_string(NULL); 1843*0Sstevel@tonic-gate s->screen = packet_get_int(); 1844*0Sstevel@tonic-gate packet_check_eom(); 1845*0Sstevel@tonic-gate 1846*0Sstevel@tonic-gate success = session_setup_x11fwd(s); 1847*0Sstevel@tonic-gate if (!success) { 1848*0Sstevel@tonic-gate xfree(s->auth_proto); 1849*0Sstevel@tonic-gate xfree(s->auth_data); 1850*0Sstevel@tonic-gate s->auth_proto = NULL; 1851*0Sstevel@tonic-gate s->auth_data = NULL; 1852*0Sstevel@tonic-gate } 1853*0Sstevel@tonic-gate return success; 1854*0Sstevel@tonic-gate } 1855*0Sstevel@tonic-gate 1856*0Sstevel@tonic-gate static int 1857*0Sstevel@tonic-gate session_shell_req(Session *s) 1858*0Sstevel@tonic-gate { 1859*0Sstevel@tonic-gate packet_check_eom(); 1860*0Sstevel@tonic-gate do_exec(s, NULL); 1861*0Sstevel@tonic-gate return 1; 1862*0Sstevel@tonic-gate } 1863*0Sstevel@tonic-gate 1864*0Sstevel@tonic-gate static int 1865*0Sstevel@tonic-gate session_exec_req(Session *s) 1866*0Sstevel@tonic-gate { 1867*0Sstevel@tonic-gate u_int len; 1868*0Sstevel@tonic-gate char *command = packet_get_string(&len); 1869*0Sstevel@tonic-gate packet_check_eom(); 1870*0Sstevel@tonic-gate do_exec(s, command); 1871*0Sstevel@tonic-gate xfree(command); 1872*0Sstevel@tonic-gate return 1; 1873*0Sstevel@tonic-gate } 1874*0Sstevel@tonic-gate 1875*0Sstevel@tonic-gate static int 1876*0Sstevel@tonic-gate session_auth_agent_req(Session *s) 1877*0Sstevel@tonic-gate { 1878*0Sstevel@tonic-gate static int called = 0; 1879*0Sstevel@tonic-gate packet_check_eom(); 1880*0Sstevel@tonic-gate if (no_agent_forwarding_flag) { 1881*0Sstevel@tonic-gate debug("session_auth_agent_req: no_agent_forwarding_flag"); 1882*0Sstevel@tonic-gate return 0; 1883*0Sstevel@tonic-gate } 1884*0Sstevel@tonic-gate if (called) { 1885*0Sstevel@tonic-gate return 0; 1886*0Sstevel@tonic-gate } else { 1887*0Sstevel@tonic-gate called = 1; 1888*0Sstevel@tonic-gate return auth_input_request_forwarding(s->pw); 1889*0Sstevel@tonic-gate } 1890*0Sstevel@tonic-gate } 1891*0Sstevel@tonic-gate 1892*0Sstevel@tonic-gate static int 1893*0Sstevel@tonic-gate session_loc_env_check(char *var, char *val) 1894*0Sstevel@tonic-gate { 1895*0Sstevel@tonic-gate char *current; 1896*0Sstevel@tonic-gate int cat, ret; 1897*0Sstevel@tonic-gate 1898*0Sstevel@tonic-gate if (strcmp(var, "LANG") == 0) 1899*0Sstevel@tonic-gate cat = LC_ALL; 1900*0Sstevel@tonic-gate else if (strcmp(var, "LC_ALL") == 0) 1901*0Sstevel@tonic-gate cat = LC_ALL; 1902*0Sstevel@tonic-gate else if (strcmp(var, "LC_CTYPE") == 0) 1903*0Sstevel@tonic-gate cat = LC_CTYPE; 1904*0Sstevel@tonic-gate else if (strcmp(var, "LC_COLLATE") == 0) 1905*0Sstevel@tonic-gate cat = LC_COLLATE; 1906*0Sstevel@tonic-gate else if (strcmp(var, "LC_TIME") == 0) 1907*0Sstevel@tonic-gate cat = LC_TIME; 1908*0Sstevel@tonic-gate else if (strcmp(var, "LC_NUMERIC") == 0) 1909*0Sstevel@tonic-gate cat = LC_NUMERIC; 1910*0Sstevel@tonic-gate else if (strcmp(var, "LC_MONETARY") == 0) 1911*0Sstevel@tonic-gate cat = LC_MONETARY; 1912*0Sstevel@tonic-gate else if (strcmp(var, "LC_MESSAGES") == 0) 1913*0Sstevel@tonic-gate cat = LC_MESSAGES; 1914*0Sstevel@tonic-gate 1915*0Sstevel@tonic-gate if ((current = setlocale(cat, NULL)) != NULL) 1916*0Sstevel@tonic-gate current = xstrdup(current); 1917*0Sstevel@tonic-gate 1918*0Sstevel@tonic-gate ret = (setlocale(cat, val) != NULL); 1919*0Sstevel@tonic-gate (void) setlocale(cat, current); 1920*0Sstevel@tonic-gate return (ret); 1921*0Sstevel@tonic-gate } 1922*0Sstevel@tonic-gate 1923*0Sstevel@tonic-gate static int 1924*0Sstevel@tonic-gate session_env_req(Session *s) 1925*0Sstevel@tonic-gate { 1926*0Sstevel@tonic-gate Channel *c; 1927*0Sstevel@tonic-gate char *var, *val, *e; 1928*0Sstevel@tonic-gate char **p; 1929*0Sstevel@tonic-gate size_t len; 1930*0Sstevel@tonic-gate int ret = 0; 1931*0Sstevel@tonic-gate 1932*0Sstevel@tonic-gate /* Get var/val from the rest of this packet */ 1933*0Sstevel@tonic-gate var = packet_get_string(NULL); 1934*0Sstevel@tonic-gate val = packet_get_string(NULL); 1935*0Sstevel@tonic-gate 1936*0Sstevel@tonic-gate /* 1937*0Sstevel@tonic-gate * We'll need the channel ID for the packet_send_debug messages, 1938*0Sstevel@tonic-gate * so get it now. 1939*0Sstevel@tonic-gate */ 1940*0Sstevel@tonic-gate if ((c = channel_lookup(s->chanid)) == NULL) 1941*0Sstevel@tonic-gate goto done; /* shouldn't happen! */ 1942*0Sstevel@tonic-gate 1943*0Sstevel@tonic-gate debug2("Received request for environment variable %s=%s", var, val); 1944*0Sstevel@tonic-gate 1945*0Sstevel@tonic-gate /* For now allow only LANG and LC_* */ 1946*0Sstevel@tonic-gate if (strcmp(var, "LANG") != 0 && strncmp(var, "LC_", 3) != 0) { 1947*0Sstevel@tonic-gate debug2("Rejecting request for environment variable %s", var); 1948*0Sstevel@tonic-gate goto done; 1949*0Sstevel@tonic-gate } 1950*0Sstevel@tonic-gate 1951*0Sstevel@tonic-gate if (!session_loc_env_check(var, val)) { 1952*0Sstevel@tonic-gate packet_send_debug(gettext("Missing locale support for %s=%s"), 1953*0Sstevel@tonic-gate var, val); 1954*0Sstevel@tonic-gate goto done; 1955*0Sstevel@tonic-gate } 1956*0Sstevel@tonic-gate 1957*0Sstevel@tonic-gate packet_send_debug(gettext("Channel %d set: %s=%s"), c->remote_id, 1958*0Sstevel@tonic-gate var, val); 1959*0Sstevel@tonic-gate 1960*0Sstevel@tonic-gate /* 1961*0Sstevel@tonic-gate * Always append new environment variables without regard to old 1962*0Sstevel@tonic-gate * ones being overriden. The way these are actually added to 1963*0Sstevel@tonic-gate * the environment of the session process later settings 1964*0Sstevel@tonic-gate * override earlier ones; see copy_environment(). 1965*0Sstevel@tonic-gate */ 1966*0Sstevel@tonic-gate if (s->env == NULL) { 1967*0Sstevel@tonic-gate char **env; 1968*0Sstevel@tonic-gate 1969*0Sstevel@tonic-gate env = xmalloc(sizeof (char **) * 2); 1970*0Sstevel@tonic-gate memset(env, 0, sizeof (char **) * 2); 1971*0Sstevel@tonic-gate 1972*0Sstevel@tonic-gate s->env = env; 1973*0Sstevel@tonic-gate p = env; 1974*0Sstevel@tonic-gate } else { 1975*0Sstevel@tonic-gate for (p = s->env; *p != NULL ; p++); 1976*0Sstevel@tonic-gate 1977*0Sstevel@tonic-gate s->env = xrealloc(s->env, (p - s->env + 2) * sizeof (char **)); 1978*0Sstevel@tonic-gate 1979*0Sstevel@tonic-gate for (p = s->env; *p != NULL ; p++); 1980*0Sstevel@tonic-gate } 1981*0Sstevel@tonic-gate 1982*0Sstevel@tonic-gate len = snprintf(NULL, 0, "%s=%s", var, val); 1983*0Sstevel@tonic-gate e = xmalloc(len + 1); 1984*0Sstevel@tonic-gate (void) snprintf(e, len + 1, "%s=%s", var, val); 1985*0Sstevel@tonic-gate 1986*0Sstevel@tonic-gate (*p++) = e; 1987*0Sstevel@tonic-gate *p = NULL; 1988*0Sstevel@tonic-gate 1989*0Sstevel@tonic-gate ret = 1; 1990*0Sstevel@tonic-gate 1991*0Sstevel@tonic-gate done: 1992*0Sstevel@tonic-gate xfree(var); 1993*0Sstevel@tonic-gate xfree(val); 1994*0Sstevel@tonic-gate 1995*0Sstevel@tonic-gate return (ret); 1996*0Sstevel@tonic-gate } 1997*0Sstevel@tonic-gate 1998*0Sstevel@tonic-gate static void 1999*0Sstevel@tonic-gate session_free_env(char ***envp) 2000*0Sstevel@tonic-gate { 2001*0Sstevel@tonic-gate char **env, **p; 2002*0Sstevel@tonic-gate 2003*0Sstevel@tonic-gate if (envp == NULL || *envp == NULL) 2004*0Sstevel@tonic-gate return; 2005*0Sstevel@tonic-gate 2006*0Sstevel@tonic-gate env = *envp; 2007*0Sstevel@tonic-gate 2008*0Sstevel@tonic-gate *envp = NULL; 2009*0Sstevel@tonic-gate 2010*0Sstevel@tonic-gate for (p = env; *p != NULL; p++) 2011*0Sstevel@tonic-gate xfree(*p); 2012*0Sstevel@tonic-gate 2013*0Sstevel@tonic-gate xfree(env); 2014*0Sstevel@tonic-gate } 2015*0Sstevel@tonic-gate 2016*0Sstevel@tonic-gate int 2017*0Sstevel@tonic-gate session_input_channel_req(Channel *c, const char *rtype) 2018*0Sstevel@tonic-gate { 2019*0Sstevel@tonic-gate int success = 0; 2020*0Sstevel@tonic-gate Session *s; 2021*0Sstevel@tonic-gate 2022*0Sstevel@tonic-gate if ((s = session_by_channel(c->self)) == NULL) { 2023*0Sstevel@tonic-gate log("session_input_channel_req: no session %d req %.100s", 2024*0Sstevel@tonic-gate c->self, rtype); 2025*0Sstevel@tonic-gate return 0; 2026*0Sstevel@tonic-gate } 2027*0Sstevel@tonic-gate debug("session_input_channel_req: session %d req %s", s->self, rtype); 2028*0Sstevel@tonic-gate 2029*0Sstevel@tonic-gate /* 2030*0Sstevel@tonic-gate * a session is in LARVAL state until a shell, a command 2031*0Sstevel@tonic-gate * or a subsystem is executed 2032*0Sstevel@tonic-gate */ 2033*0Sstevel@tonic-gate if (c->type == SSH_CHANNEL_LARVAL) { 2034*0Sstevel@tonic-gate if (strcmp(rtype, "shell") == 0) { 2035*0Sstevel@tonic-gate success = session_shell_req(s); 2036*0Sstevel@tonic-gate } else if (strcmp(rtype, "exec") == 0) { 2037*0Sstevel@tonic-gate success = session_exec_req(s); 2038*0Sstevel@tonic-gate } else if (strcmp(rtype, "pty-req") == 0) { 2039*0Sstevel@tonic-gate success = session_pty_req(s); 2040*0Sstevel@tonic-gate } else if (strcmp(rtype, "x11-req") == 0) { 2041*0Sstevel@tonic-gate success = session_x11_req(s); 2042*0Sstevel@tonic-gate } else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) { 2043*0Sstevel@tonic-gate success = session_auth_agent_req(s); 2044*0Sstevel@tonic-gate } else if (strcmp(rtype, "subsystem") == 0) { 2045*0Sstevel@tonic-gate success = session_subsystem_req(s); 2046*0Sstevel@tonic-gate } else if (strcmp(rtype, "env") == 0) { 2047*0Sstevel@tonic-gate success = session_env_req(s); 2048*0Sstevel@tonic-gate } 2049*0Sstevel@tonic-gate } 2050*0Sstevel@tonic-gate if (strcmp(rtype, "window-change") == 0) { 2051*0Sstevel@tonic-gate success = session_window_change_req(s); 2052*0Sstevel@tonic-gate } 2053*0Sstevel@tonic-gate return success; 2054*0Sstevel@tonic-gate } 2055*0Sstevel@tonic-gate 2056*0Sstevel@tonic-gate void 2057*0Sstevel@tonic-gate session_set_fds(Session *s, int fdin, int fdout, int fderr) 2058*0Sstevel@tonic-gate { 2059*0Sstevel@tonic-gate if (!compat20) 2060*0Sstevel@tonic-gate fatal("session_set_fds: called for proto != 2.0"); 2061*0Sstevel@tonic-gate /* 2062*0Sstevel@tonic-gate * now that have a child and a pipe to the child, 2063*0Sstevel@tonic-gate * we can activate our channel and register the fd's 2064*0Sstevel@tonic-gate */ 2065*0Sstevel@tonic-gate if (s->chanid == -1) 2066*0Sstevel@tonic-gate fatal("no channel for session %d", s->self); 2067*0Sstevel@tonic-gate channel_set_fds(s->chanid, 2068*0Sstevel@tonic-gate fdout, fdin, fderr, 2069*0Sstevel@tonic-gate fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, 2070*0Sstevel@tonic-gate 1, 2071*0Sstevel@tonic-gate CHAN_SES_WINDOW_DEFAULT); 2072*0Sstevel@tonic-gate } 2073*0Sstevel@tonic-gate 2074*0Sstevel@tonic-gate /* 2075*0Sstevel@tonic-gate * Function to perform pty cleanup. Also called if we get aborted abnormally 2076*0Sstevel@tonic-gate * (e.g., due to a dropped connection). 2077*0Sstevel@tonic-gate */ 2078*0Sstevel@tonic-gate void 2079*0Sstevel@tonic-gate session_pty_cleanup2(void *session) 2080*0Sstevel@tonic-gate { 2081*0Sstevel@tonic-gate Session *s = session; 2082*0Sstevel@tonic-gate 2083*0Sstevel@tonic-gate if (s == NULL) { 2084*0Sstevel@tonic-gate error("session_pty_cleanup: no session"); 2085*0Sstevel@tonic-gate return; 2086*0Sstevel@tonic-gate } 2087*0Sstevel@tonic-gate if (s->ttyfd == -1) 2088*0Sstevel@tonic-gate return; 2089*0Sstevel@tonic-gate 2090*0Sstevel@tonic-gate debug("session_pty_cleanup: session %d release %s", s->self, s->tty); 2091*0Sstevel@tonic-gate 2092*0Sstevel@tonic-gate #ifdef USE_PAM 2093*0Sstevel@tonic-gate session_do_pam(s, 0); 2094*0Sstevel@tonic-gate #endif /* USE_PAM */ 2095*0Sstevel@tonic-gate 2096*0Sstevel@tonic-gate /* Record that the user has logged out. */ 2097*0Sstevel@tonic-gate if (s->pid != 0) { 2098*0Sstevel@tonic-gate debug3("Recording SSHv2 channel login in utmpx/wtmpx"); 2099*0Sstevel@tonic-gate #ifdef ALTPRIVSEP 2100*0Sstevel@tonic-gate altprivsep_record_logout(s->pid); 2101*0Sstevel@tonic-gate #else /* ALTPRIVSEP */ 2102*0Sstevel@tonic-gate record_logout(s->pid, s->tty, NULL, s->pw->pw_name); 2103*0Sstevel@tonic-gate #endif /* ALTPRIVSEP */ 2104*0Sstevel@tonic-gate } 2105*0Sstevel@tonic-gate 2106*0Sstevel@tonic-gate /* Release the pseudo-tty. */ 2107*0Sstevel@tonic-gate if (getuid() == 0) 2108*0Sstevel@tonic-gate pty_release(s->tty); 2109*0Sstevel@tonic-gate 2110*0Sstevel@tonic-gate /* 2111*0Sstevel@tonic-gate * Close the server side of the socket pairs. We must do this after 2112*0Sstevel@tonic-gate * the pty cleanup, so that another process doesn't get this pty 2113*0Sstevel@tonic-gate * while we're still cleaning up. 2114*0Sstevel@tonic-gate */ 2115*0Sstevel@tonic-gate if (close(s->ptymaster) < 0) 2116*0Sstevel@tonic-gate error("close(s->ptymaster/%d): %s", s->ptymaster, strerror(errno)); 2117*0Sstevel@tonic-gate 2118*0Sstevel@tonic-gate /* unlink pty from session */ 2119*0Sstevel@tonic-gate s->ttyfd = -1; 2120*0Sstevel@tonic-gate } 2121*0Sstevel@tonic-gate 2122*0Sstevel@tonic-gate void 2123*0Sstevel@tonic-gate session_pty_cleanup(void *session) 2124*0Sstevel@tonic-gate { 2125*0Sstevel@tonic-gate PRIVSEP(session_pty_cleanup2(session)); 2126*0Sstevel@tonic-gate } 2127*0Sstevel@tonic-gate 2128*0Sstevel@tonic-gate static char * 2129*0Sstevel@tonic-gate sig2name(int sig) 2130*0Sstevel@tonic-gate { 2131*0Sstevel@tonic-gate #define SSH_SIG(x) if (sig == SIG ## x) return #x 2132*0Sstevel@tonic-gate SSH_SIG(ABRT); 2133*0Sstevel@tonic-gate SSH_SIG(ALRM); 2134*0Sstevel@tonic-gate SSH_SIG(FPE); 2135*0Sstevel@tonic-gate SSH_SIG(HUP); 2136*0Sstevel@tonic-gate SSH_SIG(ILL); 2137*0Sstevel@tonic-gate SSH_SIG(INT); 2138*0Sstevel@tonic-gate SSH_SIG(KILL); 2139*0Sstevel@tonic-gate SSH_SIG(PIPE); 2140*0Sstevel@tonic-gate SSH_SIG(QUIT); 2141*0Sstevel@tonic-gate SSH_SIG(SEGV); 2142*0Sstevel@tonic-gate SSH_SIG(TERM); 2143*0Sstevel@tonic-gate SSH_SIG(USR1); 2144*0Sstevel@tonic-gate SSH_SIG(USR2); 2145*0Sstevel@tonic-gate #undef SSH_SIG 2146*0Sstevel@tonic-gate return "SIG@openssh.com"; 2147*0Sstevel@tonic-gate } 2148*0Sstevel@tonic-gate 2149*0Sstevel@tonic-gate static void 2150*0Sstevel@tonic-gate session_exit_message(Session *s, int status) 2151*0Sstevel@tonic-gate { 2152*0Sstevel@tonic-gate Channel *c; 2153*0Sstevel@tonic-gate 2154*0Sstevel@tonic-gate if ((c = channel_lookup(s->chanid)) == NULL) 2155*0Sstevel@tonic-gate fatal("session_exit_message: session %d: no channel %d", 2156*0Sstevel@tonic-gate s->self, s->chanid); 2157*0Sstevel@tonic-gate debug("session_exit_message: session %d channel %d pid %ld", 2158*0Sstevel@tonic-gate s->self, s->chanid, (long)s->pid); 2159*0Sstevel@tonic-gate 2160*0Sstevel@tonic-gate if (WIFEXITED(status)) { 2161*0Sstevel@tonic-gate channel_request_start(s->chanid, "exit-status", 0); 2162*0Sstevel@tonic-gate packet_put_int(WEXITSTATUS(status)); 2163*0Sstevel@tonic-gate packet_send(); 2164*0Sstevel@tonic-gate } else if (WIFSIGNALED(status)) { 2165*0Sstevel@tonic-gate channel_request_start(s->chanid, "exit-signal", 0); 2166*0Sstevel@tonic-gate packet_put_cstring(sig2name(WTERMSIG(status))); 2167*0Sstevel@tonic-gate #ifdef WCOREDUMP 2168*0Sstevel@tonic-gate packet_put_char(WCOREDUMP(status)); 2169*0Sstevel@tonic-gate #else /* WCOREDUMP */ 2170*0Sstevel@tonic-gate packet_put_char(0); 2171*0Sstevel@tonic-gate #endif /* WCOREDUMP */ 2172*0Sstevel@tonic-gate packet_put_cstring(""); 2173*0Sstevel@tonic-gate packet_put_cstring(""); 2174*0Sstevel@tonic-gate packet_send(); 2175*0Sstevel@tonic-gate } else { 2176*0Sstevel@tonic-gate /* Some weird exit cause. Just exit. */ 2177*0Sstevel@tonic-gate packet_disconnect("wait returned status %04x.", status); 2178*0Sstevel@tonic-gate } 2179*0Sstevel@tonic-gate 2180*0Sstevel@tonic-gate /* Ok to close channel now */ 2181*0Sstevel@tonic-gate channel_set_wait_for_exit(s->chanid, 0); 2182*0Sstevel@tonic-gate 2183*0Sstevel@tonic-gate /* disconnect channel */ 2184*0Sstevel@tonic-gate debug("session_exit_message: release channel %d", s->chanid); 2185*0Sstevel@tonic-gate channel_cancel_cleanup(s->chanid); 2186*0Sstevel@tonic-gate /* 2187*0Sstevel@tonic-gate * emulate a write failure with 'chan_write_failed', nobody will be 2188*0Sstevel@tonic-gate * interested in data we write. 2189*0Sstevel@tonic-gate * Note that we must not call 'chan_read_failed', since there could 2190*0Sstevel@tonic-gate * be some more data waiting in the pipe. 2191*0Sstevel@tonic-gate */ 2192*0Sstevel@tonic-gate if (c->ostate != CHAN_OUTPUT_CLOSED) 2193*0Sstevel@tonic-gate chan_write_failed(c); 2194*0Sstevel@tonic-gate s->chanid = -1; 2195*0Sstevel@tonic-gate } 2196*0Sstevel@tonic-gate 2197*0Sstevel@tonic-gate void 2198*0Sstevel@tonic-gate session_close(Session *s) 2199*0Sstevel@tonic-gate { 2200*0Sstevel@tonic-gate debug("session_close: session %d pid %ld", s->self, (long)s->pid); 2201*0Sstevel@tonic-gate if (s->ttyfd != -1) { 2202*0Sstevel@tonic-gate fatal_remove_cleanup(session_pty_cleanup, (void *)s); 2203*0Sstevel@tonic-gate session_pty_cleanup(s); 2204*0Sstevel@tonic-gate } 2205*0Sstevel@tonic-gate if (s->term) 2206*0Sstevel@tonic-gate xfree(s->term); 2207*0Sstevel@tonic-gate if (s->display) 2208*0Sstevel@tonic-gate xfree(s->display); 2209*0Sstevel@tonic-gate if (s->auth_display) 2210*0Sstevel@tonic-gate xfree(s->auth_display); 2211*0Sstevel@tonic-gate if (s->auth_data) 2212*0Sstevel@tonic-gate xfree(s->auth_data); 2213*0Sstevel@tonic-gate if (s->auth_proto) 2214*0Sstevel@tonic-gate xfree(s->auth_proto); 2215*0Sstevel@tonic-gate if (s->command) 2216*0Sstevel@tonic-gate xfree(s->command); 2217*0Sstevel@tonic-gate session_free_env(&s->env); 2218*0Sstevel@tonic-gate s->used = 0; 2219*0Sstevel@tonic-gate session_proctitle(s); 2220*0Sstevel@tonic-gate } 2221*0Sstevel@tonic-gate 2222*0Sstevel@tonic-gate void 2223*0Sstevel@tonic-gate session_close_by_pid(pid_t pid, int status) 2224*0Sstevel@tonic-gate { 2225*0Sstevel@tonic-gate Session *s = session_by_pid(pid); 2226*0Sstevel@tonic-gate if (s == NULL) { 2227*0Sstevel@tonic-gate debug("session_close_by_pid: no session for pid %ld", 2228*0Sstevel@tonic-gate (long)pid); 2229*0Sstevel@tonic-gate return; 2230*0Sstevel@tonic-gate } 2231*0Sstevel@tonic-gate if (s->chanid != -1) 2232*0Sstevel@tonic-gate session_exit_message(s, status); 2233*0Sstevel@tonic-gate session_close(s); 2234*0Sstevel@tonic-gate } 2235*0Sstevel@tonic-gate 2236*0Sstevel@tonic-gate /* 2237*0Sstevel@tonic-gate * this is called when a channel dies before 2238*0Sstevel@tonic-gate * the session 'child' itself dies 2239*0Sstevel@tonic-gate */ 2240*0Sstevel@tonic-gate void 2241*0Sstevel@tonic-gate session_close_by_channel(int id, void *arg) 2242*0Sstevel@tonic-gate { 2243*0Sstevel@tonic-gate Session *s = session_by_channel(id); 2244*0Sstevel@tonic-gate if (s == NULL) { 2245*0Sstevel@tonic-gate debug("session_close_by_channel: no session for id %d", id); 2246*0Sstevel@tonic-gate return; 2247*0Sstevel@tonic-gate } 2248*0Sstevel@tonic-gate debug("session_close_by_channel: channel %d child %ld", 2249*0Sstevel@tonic-gate id, (long)s->pid); 2250*0Sstevel@tonic-gate if (s->pid != 0) { 2251*0Sstevel@tonic-gate debug("session_close_by_channel: channel %d: has child", id); 2252*0Sstevel@tonic-gate /* 2253*0Sstevel@tonic-gate * delay detach of session, but release pty, since 2254*0Sstevel@tonic-gate * the fd's to the child are already closed 2255*0Sstevel@tonic-gate */ 2256*0Sstevel@tonic-gate if (s->ttyfd != -1) { 2257*0Sstevel@tonic-gate fatal_remove_cleanup(session_pty_cleanup, (void *)s); 2258*0Sstevel@tonic-gate session_pty_cleanup(s); 2259*0Sstevel@tonic-gate } 2260*0Sstevel@tonic-gate return; 2261*0Sstevel@tonic-gate } 2262*0Sstevel@tonic-gate /* detach by removing callback */ 2263*0Sstevel@tonic-gate channel_cancel_cleanup(s->chanid); 2264*0Sstevel@tonic-gate s->chanid = -1; 2265*0Sstevel@tonic-gate session_close(s); 2266*0Sstevel@tonic-gate } 2267*0Sstevel@tonic-gate 2268*0Sstevel@tonic-gate void 2269*0Sstevel@tonic-gate session_destroy_all(void (*closefunc)(Session *)) 2270*0Sstevel@tonic-gate { 2271*0Sstevel@tonic-gate int i; 2272*0Sstevel@tonic-gate for (i = 0; i < MAX_SESSIONS; i++) { 2273*0Sstevel@tonic-gate Session *s = &sessions[i]; 2274*0Sstevel@tonic-gate if (s->used) { 2275*0Sstevel@tonic-gate if (closefunc != NULL) 2276*0Sstevel@tonic-gate closefunc(s); 2277*0Sstevel@tonic-gate else 2278*0Sstevel@tonic-gate session_close(s); 2279*0Sstevel@tonic-gate } 2280*0Sstevel@tonic-gate } 2281*0Sstevel@tonic-gate } 2282*0Sstevel@tonic-gate 2283*0Sstevel@tonic-gate static char * 2284*0Sstevel@tonic-gate session_tty_list(void) 2285*0Sstevel@tonic-gate { 2286*0Sstevel@tonic-gate static char buf[1024]; 2287*0Sstevel@tonic-gate int i; 2288*0Sstevel@tonic-gate buf[0] = '\0'; 2289*0Sstevel@tonic-gate for (i = 0; i < MAX_SESSIONS; i++) { 2290*0Sstevel@tonic-gate Session *s = &sessions[i]; 2291*0Sstevel@tonic-gate if (s->used && s->ttyfd != -1) { 2292*0Sstevel@tonic-gate if (buf[0] != '\0') 2293*0Sstevel@tonic-gate strlcat(buf, ",", sizeof buf); 2294*0Sstevel@tonic-gate strlcat(buf, strrchr(s->tty, '/') + 1, sizeof buf); 2295*0Sstevel@tonic-gate } 2296*0Sstevel@tonic-gate } 2297*0Sstevel@tonic-gate if (buf[0] == '\0') 2298*0Sstevel@tonic-gate strlcpy(buf, "notty", sizeof buf); 2299*0Sstevel@tonic-gate return buf; 2300*0Sstevel@tonic-gate } 2301*0Sstevel@tonic-gate 2302*0Sstevel@tonic-gate void 2303*0Sstevel@tonic-gate session_proctitle(Session *s) 2304*0Sstevel@tonic-gate { 2305*0Sstevel@tonic-gate if (s->pw == NULL) 2306*0Sstevel@tonic-gate error("no user for session %d", s->self); 2307*0Sstevel@tonic-gate else 2308*0Sstevel@tonic-gate setproctitle("%s@%s", s->pw->pw_name, session_tty_list()); 2309*0Sstevel@tonic-gate } 2310*0Sstevel@tonic-gate 2311*0Sstevel@tonic-gate int 2312*0Sstevel@tonic-gate session_setup_x11fwd(Session *s) 2313*0Sstevel@tonic-gate { 2314*0Sstevel@tonic-gate struct stat st; 2315*0Sstevel@tonic-gate char display[512], auth_display[512]; 2316*0Sstevel@tonic-gate char hostname[MAXHOSTNAMELEN]; 2317*0Sstevel@tonic-gate 2318*0Sstevel@tonic-gate if (no_x11_forwarding_flag) { 2319*0Sstevel@tonic-gate packet_send_debug("X11 forwarding disabled in user configuration file."); 2320*0Sstevel@tonic-gate return 0; 2321*0Sstevel@tonic-gate } 2322*0Sstevel@tonic-gate if (!options.x11_forwarding) { 2323*0Sstevel@tonic-gate debug("X11 forwarding disabled in server configuration file."); 2324*0Sstevel@tonic-gate return 0; 2325*0Sstevel@tonic-gate } 2326*0Sstevel@tonic-gate if (!options.xauth_location || 2327*0Sstevel@tonic-gate (stat(options.xauth_location, &st) == -1)) { 2328*0Sstevel@tonic-gate packet_send_debug("No xauth program; cannot forward with spoofing."); 2329*0Sstevel@tonic-gate return 0; 2330*0Sstevel@tonic-gate } 2331*0Sstevel@tonic-gate if (options.use_login) { 2332*0Sstevel@tonic-gate packet_send_debug("X11 forwarding disabled; " 2333*0Sstevel@tonic-gate "not compatible with UseLogin=yes."); 2334*0Sstevel@tonic-gate return 0; 2335*0Sstevel@tonic-gate } 2336*0Sstevel@tonic-gate if (s->display != NULL) { 2337*0Sstevel@tonic-gate debug("X11 display already set."); 2338*0Sstevel@tonic-gate return 0; 2339*0Sstevel@tonic-gate } 2340*0Sstevel@tonic-gate if (x11_create_display_inet(options.x11_display_offset, 2341*0Sstevel@tonic-gate options.x11_use_localhost, s->single_connection, 2342*0Sstevel@tonic-gate &s->display_number) == -1) { 2343*0Sstevel@tonic-gate debug("x11_create_display_inet failed."); 2344*0Sstevel@tonic-gate return 0; 2345*0Sstevel@tonic-gate } 2346*0Sstevel@tonic-gate 2347*0Sstevel@tonic-gate /* Set up a suitable value for the DISPLAY variable. */ 2348*0Sstevel@tonic-gate if (gethostname(hostname, sizeof(hostname)) < 0) 2349*0Sstevel@tonic-gate fatal("gethostname: %.100s", strerror(errno)); 2350*0Sstevel@tonic-gate /* 2351*0Sstevel@tonic-gate * auth_display must be used as the displayname when the 2352*0Sstevel@tonic-gate * authorization entry is added with xauth(1). This will be 2353*0Sstevel@tonic-gate * different than the DISPLAY string for localhost displays. 2354*0Sstevel@tonic-gate */ 2355*0Sstevel@tonic-gate if (options.x11_use_localhost) { 2356*0Sstevel@tonic-gate snprintf(display, sizeof display, "localhost:%u.%u", 2357*0Sstevel@tonic-gate s->display_number, s->screen); 2358*0Sstevel@tonic-gate snprintf(auth_display, sizeof auth_display, "unix:%u.%u", 2359*0Sstevel@tonic-gate s->display_number, s->screen); 2360*0Sstevel@tonic-gate s->display = xstrdup(display); 2361*0Sstevel@tonic-gate s->auth_display = xstrdup(auth_display); 2362*0Sstevel@tonic-gate } else { 2363*0Sstevel@tonic-gate #ifdef IPADDR_IN_DISPLAY 2364*0Sstevel@tonic-gate struct hostent *he; 2365*0Sstevel@tonic-gate struct in_addr my_addr; 2366*0Sstevel@tonic-gate 2367*0Sstevel@tonic-gate he = gethostbyname(hostname); 2368*0Sstevel@tonic-gate if (he == NULL) { 2369*0Sstevel@tonic-gate error("Can't get IP address for X11 DISPLAY."); 2370*0Sstevel@tonic-gate packet_send_debug("Can't get IP address for X11 DISPLAY."); 2371*0Sstevel@tonic-gate return 0; 2372*0Sstevel@tonic-gate } 2373*0Sstevel@tonic-gate memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr)); 2374*0Sstevel@tonic-gate snprintf(display, sizeof display, "%.50s:%u.%u", inet_ntoa(my_addr), 2375*0Sstevel@tonic-gate s->display_number, s->screen); 2376*0Sstevel@tonic-gate #else 2377*0Sstevel@tonic-gate snprintf(display, sizeof display, "%.400s:%u.%u", hostname, 2378*0Sstevel@tonic-gate s->display_number, s->screen); 2379*0Sstevel@tonic-gate #endif 2380*0Sstevel@tonic-gate s->display = xstrdup(display); 2381*0Sstevel@tonic-gate s->auth_display = xstrdup(display); 2382*0Sstevel@tonic-gate } 2383*0Sstevel@tonic-gate 2384*0Sstevel@tonic-gate return 1; 2385*0Sstevel@tonic-gate } 2386*0Sstevel@tonic-gate 2387*0Sstevel@tonic-gate #ifdef USE_PAM 2388*0Sstevel@tonic-gate int session_do_pam_conv(int, struct pam_message **, 2389*0Sstevel@tonic-gate struct pam_response **, void *); 2390*0Sstevel@tonic-gate 2391*0Sstevel@tonic-gate static struct pam_conv session_pam_conv = { 2392*0Sstevel@tonic-gate session_do_pam_conv, 2393*0Sstevel@tonic-gate NULL 2394*0Sstevel@tonic-gate }; 2395*0Sstevel@tonic-gate 2396*0Sstevel@tonic-gate static void 2397*0Sstevel@tonic-gate session_do_pam(Session *s, int do_open) 2398*0Sstevel@tonic-gate { 2399*0Sstevel@tonic-gate int pam_retval; 2400*0Sstevel@tonic-gate char *where, *old_tty, *old_tty_copy = NULL; 2401*0Sstevel@tonic-gate struct pam_conv old_conv, *old_conv_ptr; 2402*0Sstevel@tonic-gate 2403*0Sstevel@tonic-gate if (!s || !s->authctxt || !s->authctxt->pam || !s->authctxt->pam->h) 2404*0Sstevel@tonic-gate return; 2405*0Sstevel@tonic-gate 2406*0Sstevel@tonic-gate /* Save current PAM item values */ 2407*0Sstevel@tonic-gate where = "getting PAM_CONV"; 2408*0Sstevel@tonic-gate pam_retval = pam_get_item(s->authctxt->pam->h, PAM_CONV, 2409*0Sstevel@tonic-gate (void **) &old_conv_ptr); 2410*0Sstevel@tonic-gate if (pam_retval != PAM_SUCCESS) 2411*0Sstevel@tonic-gate goto done; 2412*0Sstevel@tonic-gate old_conv = *old_conv_ptr; 2413*0Sstevel@tonic-gate 2414*0Sstevel@tonic-gate where = "getting PAM_TTY"; 2415*0Sstevel@tonic-gate pam_retval = pam_get_item(s->authctxt->pam->h, PAM_TTY, 2416*0Sstevel@tonic-gate (void **) &old_tty); 2417*0Sstevel@tonic-gate if (pam_retval != PAM_SUCCESS) 2418*0Sstevel@tonic-gate goto done; 2419*0Sstevel@tonic-gate old_tty_copy = xstrdup(old_tty); 2420*0Sstevel@tonic-gate 2421*0Sstevel@tonic-gate /* Change PAM_TTY and PAM_CONV items */ 2422*0Sstevel@tonic-gate where = "setting PAM_TTY"; 2423*0Sstevel@tonic-gate pam_retval = pam_set_item(s->authctxt->pam->h, PAM_TTY, s->tty); 2424*0Sstevel@tonic-gate if (pam_retval != PAM_SUCCESS) 2425*0Sstevel@tonic-gate goto done; 2426*0Sstevel@tonic-gate 2427*0Sstevel@tonic-gate where = "setting PAM_CONV"; 2428*0Sstevel@tonic-gate session_pam_conv.appdata_ptr = s; 2429*0Sstevel@tonic-gate pam_retval = pam_set_item(s->authctxt->pam->h, 2430*0Sstevel@tonic-gate PAM_CONV, &session_pam_conv); 2431*0Sstevel@tonic-gate if (pam_retval != PAM_SUCCESS) 2432*0Sstevel@tonic-gate goto done; 2433*0Sstevel@tonic-gate 2434*0Sstevel@tonic-gate /* Call pam_open/close_session() */ 2435*0Sstevel@tonic-gate if (do_open) { 2436*0Sstevel@tonic-gate where = "calling pam_open_session()"; 2437*0Sstevel@tonic-gate pam_retval = pam_open_session(s->authctxt->pam->h, 0); 2438*0Sstevel@tonic-gate } 2439*0Sstevel@tonic-gate else { 2440*0Sstevel@tonic-gate where = "calling pam_close_session()"; 2441*0Sstevel@tonic-gate pam_retval = pam_close_session(s->authctxt->pam->h, 0); 2442*0Sstevel@tonic-gate } 2443*0Sstevel@tonic-gate 2444*0Sstevel@tonic-gate /* Reset PAM_TTY and PAM_CONV items to previous values */ 2445*0Sstevel@tonic-gate where = "setting PAM_TTY"; 2446*0Sstevel@tonic-gate pam_retval = pam_set_item(s->authctxt->pam->h, PAM_TTY, old_tty_copy); 2447*0Sstevel@tonic-gate if (pam_retval != PAM_SUCCESS) 2448*0Sstevel@tonic-gate goto done; 2449*0Sstevel@tonic-gate 2450*0Sstevel@tonic-gate where = "setting PAM_CONV"; 2451*0Sstevel@tonic-gate pam_retval = pam_set_item(s->authctxt->pam->h, PAM_CONV, &old_conv); 2452*0Sstevel@tonic-gate if (pam_retval != PAM_SUCCESS) 2453*0Sstevel@tonic-gate goto done; 2454*0Sstevel@tonic-gate 2455*0Sstevel@tonic-gate session_pam_conv.appdata_ptr = NULL; 2456*0Sstevel@tonic-gate 2457*0Sstevel@tonic-gate done: 2458*0Sstevel@tonic-gate if (old_tty_copy) 2459*0Sstevel@tonic-gate xfree(old_tty_copy); 2460*0Sstevel@tonic-gate 2461*0Sstevel@tonic-gate if (pam_retval == PAM_SUCCESS) 2462*0Sstevel@tonic-gate return; 2463*0Sstevel@tonic-gate 2464*0Sstevel@tonic-gate /* fatal()? probably not... */ 2465*0Sstevel@tonic-gate log("PAM failed[%d] while %s: %s", pam_retval, where, 2466*0Sstevel@tonic-gate PAM_STRERROR(s->authctxt->pam->h, pam_retval)); 2467*0Sstevel@tonic-gate } 2468*0Sstevel@tonic-gate 2469*0Sstevel@tonic-gate int 2470*0Sstevel@tonic-gate session_do_pam_conv(int num_prompts, 2471*0Sstevel@tonic-gate struct pam_message **prompts, 2472*0Sstevel@tonic-gate struct pam_response **resp, 2473*0Sstevel@tonic-gate void *app_data) 2474*0Sstevel@tonic-gate { 2475*0Sstevel@tonic-gate Session *s = (Session *) app_data; 2476*0Sstevel@tonic-gate 2477*0Sstevel@tonic-gate struct pam_response *reply; 2478*0Sstevel@tonic-gate int count; 2479*0Sstevel@tonic-gate char *prompt; 2480*0Sstevel@tonic-gate 2481*0Sstevel@tonic-gate if (channel_lookup(s->chanid) == NULL) 2482*0Sstevel@tonic-gate return PAM_CONV_ERR; 2483*0Sstevel@tonic-gate 2484*0Sstevel@tonic-gate /* PAM will free this later */ 2485*0Sstevel@tonic-gate reply = xmalloc(num_prompts * sizeof(*reply)); 2486*0Sstevel@tonic-gate 2487*0Sstevel@tonic-gate (void) memset(reply, 0, num_prompts * sizeof(*reply)); 2488*0Sstevel@tonic-gate for (count = 0; count < num_prompts; count++) { 2489*0Sstevel@tonic-gate switch(PAM_MSG_MEMBER(prompts, count, msg_style)) { 2490*0Sstevel@tonic-gate case PAM_TEXT_INFO: 2491*0Sstevel@tonic-gate /* Write to stdout of channel */ 2492*0Sstevel@tonic-gate prompt = PAM_MSG_MEMBER(prompts, count, msg); 2493*0Sstevel@tonic-gate if (prompt != NULL && s->ttyfd != -1) { 2494*0Sstevel@tonic-gate debug2("session_do_pam_conv: text info " 2495*0Sstevel@tonic-gate "prompt: %s", prompt); 2496*0Sstevel@tonic-gate (void) write(s->ttyfd, prompt, strlen(prompt)); 2497*0Sstevel@tonic-gate (void) write(s->ttyfd, "\n", 1); 2498*0Sstevel@tonic-gate } 2499*0Sstevel@tonic-gate reply[count].resp = xstrdup(""); 2500*0Sstevel@tonic-gate reply[count].resp_retcode = PAM_SUCCESS; 2501*0Sstevel@tonic-gate break; 2502*0Sstevel@tonic-gate case PAM_ERROR_MSG: 2503*0Sstevel@tonic-gate /* Write to stderr of channel */ 2504*0Sstevel@tonic-gate prompt = PAM_MSG_MEMBER(prompts, count, msg); 2505*0Sstevel@tonic-gate if (prompt != NULL && s->ttyfd != -1) { 2506*0Sstevel@tonic-gate debug2("session_do_pam_conv: error " 2507*0Sstevel@tonic-gate "prompt: %s", prompt); 2508*0Sstevel@tonic-gate (void) write(s->ttyfd, prompt, strlen(prompt)); 2509*0Sstevel@tonic-gate (void) write(s->ttyfd, "\n", 1); 2510*0Sstevel@tonic-gate } 2511*0Sstevel@tonic-gate reply[count].resp = xstrdup(""); 2512*0Sstevel@tonic-gate reply[count].resp_retcode = PAM_SUCCESS; 2513*0Sstevel@tonic-gate break; 2514*0Sstevel@tonic-gate case PAM_PROMPT_ECHO_ON: 2515*0Sstevel@tonic-gate case PAM_PROMPT_ECHO_OFF: 2516*0Sstevel@tonic-gate /* 2517*0Sstevel@tonic-gate * XXX Someday add support for echo on/off prompts 2518*0Sstevel@tonic-gate * here on sessions with ttys. 2519*0Sstevel@tonic-gate */ 2520*0Sstevel@tonic-gate default: 2521*0Sstevel@tonic-gate xfree(reply); 2522*0Sstevel@tonic-gate return PAM_CONV_ERR; 2523*0Sstevel@tonic-gate } 2524*0Sstevel@tonic-gate } 2525*0Sstevel@tonic-gate 2526*0Sstevel@tonic-gate *resp = reply; 2527*0Sstevel@tonic-gate 2528*0Sstevel@tonic-gate return PAM_SUCCESS; 2529*0Sstevel@tonic-gate } 2530*0Sstevel@tonic-gate #endif /* USE_PAM */ 2531*0Sstevel@tonic-gate 2532*0Sstevel@tonic-gate static void 2533*0Sstevel@tonic-gate do_authenticated2(Authctxt *authctxt) 2534*0Sstevel@tonic-gate { 2535*0Sstevel@tonic-gate server_loop2(authctxt); 2536*0Sstevel@tonic-gate } 2537