xref: /freebsd/crypto/openssh/session.c (revision 3620d70511dc8bf45752028dac0af6f157ec6146)
10fdf8faeSEd Maste /* $OpenBSD: session.c,v 1.338 2024/05/17 00:30:24 djm Exp $ */
2a04a10f8SKris Kennaway /*
3a04a10f8SKris Kennaway  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4a04a10f8SKris Kennaway  *                    All rights reserved
5c2d3a559SKris Kennaway  *
6c2d3a559SKris Kennaway  * As far as I am concerned, the code I have written for this software
7c2d3a559SKris Kennaway  * can be used freely for any purpose.  Any derived versions of this
8c2d3a559SKris Kennaway  * software must be clearly marked as such, and if the derived work is
9c2d3a559SKris Kennaway  * incompatible with the protocol description in the RFC file, it must be
10c2d3a559SKris Kennaway  * called by a name other than "ssh" or "Secure Shell".
11c2d3a559SKris Kennaway  *
12a04a10f8SKris Kennaway  * SSH2 support by Markus Friedl.
13af12a3e7SDag-Erling Smørgrav  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
14e8aafc91SKris Kennaway  *
15c2d3a559SKris Kennaway  * Redistribution and use in source and binary forms, with or without
16c2d3a559SKris Kennaway  * modification, are permitted provided that the following conditions
17c2d3a559SKris Kennaway  * are met:
18c2d3a559SKris Kennaway  * 1. Redistributions of source code must retain the above copyright
19c2d3a559SKris Kennaway  *    notice, this list of conditions and the following disclaimer.
20c2d3a559SKris Kennaway  * 2. Redistributions in binary form must reproduce the above copyright
21c2d3a559SKris Kennaway  *    notice, this list of conditions and the following disclaimer in the
22c2d3a559SKris Kennaway  *    documentation and/or other materials provided with the distribution.
23c2d3a559SKris Kennaway  *
24c2d3a559SKris Kennaway  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25c2d3a559SKris Kennaway  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26c2d3a559SKris Kennaway  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27c2d3a559SKris Kennaway  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28c2d3a559SKris Kennaway  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29c2d3a559SKris Kennaway  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30c2d3a559SKris Kennaway  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31c2d3a559SKris Kennaway  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32c2d3a559SKris Kennaway  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33c2d3a559SKris Kennaway  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34a04a10f8SKris Kennaway  */
35a04a10f8SKris Kennaway 
36a04a10f8SKris Kennaway #include "includes.h"
37a04a10f8SKris Kennaway 
38333ee039SDag-Erling Smørgrav #include <sys/types.h>
39333ee039SDag-Erling Smørgrav #ifdef HAVE_SYS_STAT_H
40333ee039SDag-Erling Smørgrav # include <sys/stat.h>
41333ee039SDag-Erling Smørgrav #endif
42333ee039SDag-Erling Smørgrav #include <sys/socket.h>
43333ee039SDag-Erling Smørgrav #include <sys/un.h>
44333ee039SDag-Erling Smørgrav #include <sys/wait.h>
45333ee039SDag-Erling Smørgrav 
46333ee039SDag-Erling Smørgrav #include <arpa/inet.h>
47333ee039SDag-Erling Smørgrav 
48acc1a9efSDag-Erling Smørgrav #include <ctype.h>
49333ee039SDag-Erling Smørgrav #include <errno.h>
50e2f6069cSDag-Erling Smørgrav #include <fcntl.h>
51333ee039SDag-Erling Smørgrav #include <grp.h>
52a0ee8cc6SDag-Erling Smørgrav #include <netdb.h>
53333ee039SDag-Erling Smørgrav #ifdef HAVE_PATHS_H
54333ee039SDag-Erling Smørgrav #include <paths.h>
55333ee039SDag-Erling Smørgrav #endif
56333ee039SDag-Erling Smørgrav #include <pwd.h>
57333ee039SDag-Erling Smørgrav #include <signal.h>
58333ee039SDag-Erling Smørgrav #include <stdio.h>
59333ee039SDag-Erling Smørgrav #include <stdlib.h>
60333ee039SDag-Erling Smørgrav #include <string.h>
6119261079SEd Maste #include <stdarg.h>
62333ee039SDag-Erling Smørgrav #include <unistd.h>
63bc5531deSDag-Erling Smørgrav #include <limits.h>
64333ee039SDag-Erling Smørgrav 
65d4af9e69SDag-Erling Smørgrav #include "openbsd-compat/sys-queue.h"
66333ee039SDag-Erling Smørgrav #include "xmalloc.h"
67a04a10f8SKris Kennaway #include "ssh.h"
68ca3176e7SBrian Feldman #include "ssh2.h"
69ca3176e7SBrian Feldman #include "sshpty.h"
70a04a10f8SKris Kennaway #include "packet.h"
71190cef3dSDag-Erling Smørgrav #include "sshbuf.h"
72190cef3dSDag-Erling Smørgrav #include "ssherr.h"
7321e764dfSDag-Erling Smørgrav #include "match.h"
74a04a10f8SKris Kennaway #include "uidswap.h"
75a04a10f8SKris Kennaway #include "channels.h"
76190cef3dSDag-Erling Smørgrav #include "sshkey.h"
77333ee039SDag-Erling Smørgrav #include "cipher.h"
78333ee039SDag-Erling Smørgrav #ifdef GSSAPI
79333ee039SDag-Erling Smørgrav #include "ssh-gss.h"
80333ee039SDag-Erling Smørgrav #endif
81333ee039SDag-Erling Smørgrav #include "hostfile.h"
82a04a10f8SKris Kennaway #include "auth.h"
83c2d3a559SKris Kennaway #include "auth-options.h"
84e4a9863fSDag-Erling Smørgrav #include "authfd.h"
85ca3176e7SBrian Feldman #include "pathnames.h"
86ca3176e7SBrian Feldman #include "log.h"
87a0ee8cc6SDag-Erling Smørgrav #include "misc.h"
88ca3176e7SBrian Feldman #include "servconf.h"
89ca3176e7SBrian Feldman #include "sshlogin.h"
90ca3176e7SBrian Feldman #include "serverloop.h"
91ca3176e7SBrian Feldman #include "canohost.h"
92ca3176e7SBrian Feldman #include "session.h"
93d4ecd108SDag-Erling Smørgrav #include "kex.h"
9480628bacSDag-Erling Smørgrav #include "monitor_wrap.h"
95d4af9e69SDag-Erling Smørgrav #include "sftp.h"
964f52dfbbSDag-Erling Smørgrav #include "atomicio.h"
97a04a10f8SKris Kennaway 
981ec0d754SDag-Erling Smørgrav #if defined(KRB5) && defined(USE_AFS)
991ec0d754SDag-Erling Smørgrav #include <kafs.h>
1001ec0d754SDag-Erling Smørgrav #endif
1011ec0d754SDag-Erling Smørgrav 
102e146993eSDag-Erling Smørgrav #ifdef WITH_SELINUX
103e146993eSDag-Erling Smørgrav #include <selinux/selinux.h>
104e146993eSDag-Erling Smørgrav #endif
105e146993eSDag-Erling Smørgrav 
1060fdf8faeSEd Maste /*
1070fdf8faeSEd Maste  * Hack for systems that do not support FD passing: allocate PTYs directly
1080fdf8faeSEd Maste  * without calling into the monitor. This requires either the post-auth
1090fdf8faeSEd Maste  * privsep process retain root privileges (see the comment in
1100fdf8faeSEd Maste  * sshd-session.c:privsep_postauth) or that PTY allocation doesn't require
1110fdf8faeSEd Maste  * privileges to begin with (e.g. Cygwin).
1120fdf8faeSEd Maste  */
1130fdf8faeSEd Maste #ifdef DISABLE_FD_PASSING
1140fdf8faeSEd Maste #define mm_pty_allocate pty_allocate
1150fdf8faeSEd Maste #endif
1160fdf8faeSEd Maste 
117cce7d346SDag-Erling Smørgrav #define IS_INTERNAL_SFTP(c) \
118cce7d346SDag-Erling Smørgrav 	(!strncmp(c, INTERNAL_SFTP_NAME, sizeof(INTERNAL_SFTP_NAME) - 1) && \
119cce7d346SDag-Erling Smørgrav 	 (c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\0' || \
120cce7d346SDag-Erling Smørgrav 	  c[sizeof(INTERNAL_SFTP_NAME) - 1] == ' ' || \
121cce7d346SDag-Erling Smørgrav 	  c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\t'))
122cce7d346SDag-Erling Smørgrav 
123a04a10f8SKris Kennaway /* func */
124a04a10f8SKris Kennaway 
125a04a10f8SKris Kennaway Session *session_new(void);
1264f52dfbbSDag-Erling Smørgrav void	session_set_fds(struct ssh *, Session *, int, int, int, int, int);
1271ec0d754SDag-Erling Smørgrav void	session_pty_cleanup(Session *);
128af12a3e7SDag-Erling Smørgrav void	session_proctitle(Session *);
1294f52dfbbSDag-Erling Smørgrav int	session_setup_x11fwd(struct ssh *, Session *);
1304f52dfbbSDag-Erling Smørgrav int	do_exec_pty(struct ssh *, Session *, const char *);
1314f52dfbbSDag-Erling Smørgrav int	do_exec_no_pty(struct ssh *, Session *, const char *);
1324f52dfbbSDag-Erling Smørgrav int	do_exec(struct ssh *, Session *, const char *);
1334f52dfbbSDag-Erling Smørgrav void	do_login(struct ssh *, Session *, const char *);
1344f52dfbbSDag-Erling Smørgrav void	do_child(struct ssh *, Session *, const char *);
135ca3176e7SBrian Feldman void	do_motd(void);
136af12a3e7SDag-Erling Smørgrav int	check_quietlogin(Session *, const char *);
137a04a10f8SKris Kennaway 
1384f52dfbbSDag-Erling Smørgrav static void do_authenticated2(struct ssh *, Authctxt *);
139af12a3e7SDag-Erling Smørgrav 
1404f52dfbbSDag-Erling Smørgrav static int session_pty_req(struct ssh *, Session *);
141a04a10f8SKris Kennaway 
142a04a10f8SKris Kennaway /* import */
143a04a10f8SKris Kennaway extern ServerOptions options;
144a04a10f8SKris Kennaway extern char *__progname;
145a04a10f8SKris Kennaway extern int debug_flag;
146ca3176e7SBrian Feldman extern u_int utmp_len;
147c2d3a559SKris Kennaway extern int startup_pipe;
148ca3176e7SBrian Feldman extern void destroy_sensitive_data(void);
149190cef3dSDag-Erling Smørgrav extern struct sshbuf *loginmsg;
15047dd1d1bSDag-Erling Smørgrav extern struct sshauthopt *auth_opts;
1516d0d51a4SKyle Evans extern char *tun_fwd_ifnames; /* serverloop.c */
152a04a10f8SKris Kennaway 
153c2d3a559SKris Kennaway /* original command from peer. */
154af12a3e7SDag-Erling Smørgrav const char *original_command = NULL;
155c2d3a559SKris Kennaway 
156a04a10f8SKris Kennaway /* data */
157d4af9e69SDag-Erling Smørgrav static int sessions_first_unused = -1;
158d4af9e69SDag-Erling Smørgrav static int sessions_nalloc = 0;
159d4af9e69SDag-Erling Smørgrav static Session *sessions = NULL;
160d4af9e69SDag-Erling Smørgrav 
161d4af9e69SDag-Erling Smørgrav #define SUBSYSTEM_NONE			0
162d4af9e69SDag-Erling Smørgrav #define SUBSYSTEM_EXT			1
163d4af9e69SDag-Erling Smørgrav #define SUBSYSTEM_INT_SFTP		2
164b15c8340SDag-Erling Smørgrav #define SUBSYSTEM_INT_SFTP_ERROR	3
165a04a10f8SKris Kennaway 
166c2d3a559SKris Kennaway #ifdef HAVE_LOGIN_CAP
16780628bacSDag-Erling Smørgrav login_cap_t *lc;
168c2d3a559SKris Kennaway #endif
169a04a10f8SKris Kennaway 
1701ec0d754SDag-Erling Smørgrav static int is_child = 0;
171acc1a9efSDag-Erling Smørgrav static int in_chroot = 0;
1721ec0d754SDag-Erling Smørgrav 
1734f52dfbbSDag-Erling Smørgrav /* File containing userauth info, if ExposeAuthInfo set */
1744f52dfbbSDag-Erling Smørgrav static char *auth_info_file = NULL;
1754f52dfbbSDag-Erling Smørgrav 
17680628bacSDag-Erling Smørgrav /* Name and directory of socket for authentication agent forwarding. */
17780628bacSDag-Erling Smørgrav static char *auth_sock_name = NULL;
17880628bacSDag-Erling Smørgrav static char *auth_sock_dir = NULL;
17980628bacSDag-Erling Smørgrav 
18080628bacSDag-Erling Smørgrav /* removes the agent forwarding socket */
18180628bacSDag-Erling Smørgrav 
18280628bacSDag-Erling Smørgrav static void
auth_sock_cleanup_proc(struct passwd * pw)1831ec0d754SDag-Erling Smørgrav auth_sock_cleanup_proc(struct passwd *pw)
18480628bacSDag-Erling Smørgrav {
18580628bacSDag-Erling Smørgrav 	if (auth_sock_name != NULL) {
18680628bacSDag-Erling Smørgrav 		temporarily_use_uid(pw);
18780628bacSDag-Erling Smørgrav 		unlink(auth_sock_name);
18880628bacSDag-Erling Smørgrav 		rmdir(auth_sock_dir);
18980628bacSDag-Erling Smørgrav 		auth_sock_name = NULL;
19080628bacSDag-Erling Smørgrav 		restore_uid();
19180628bacSDag-Erling Smørgrav 	}
19280628bacSDag-Erling Smørgrav }
19380628bacSDag-Erling Smørgrav 
19480628bacSDag-Erling Smørgrav static int
auth_input_request_forwarding(struct ssh * ssh,struct passwd * pw)1954f52dfbbSDag-Erling Smørgrav auth_input_request_forwarding(struct ssh *ssh, struct passwd * pw)
19680628bacSDag-Erling Smørgrav {
19780628bacSDag-Erling Smørgrav 	Channel *nc;
198d4af9e69SDag-Erling Smørgrav 	int sock = -1;
19980628bacSDag-Erling Smørgrav 
20080628bacSDag-Erling Smørgrav 	if (auth_sock_name != NULL) {
20180628bacSDag-Erling Smørgrav 		error("authentication forwarding requested twice.");
20280628bacSDag-Erling Smørgrav 		return 0;
20380628bacSDag-Erling Smørgrav 	}
20480628bacSDag-Erling Smørgrav 
20580628bacSDag-Erling Smørgrav 	/* Temporarily drop privileged uid for mkdir/bind. */
20680628bacSDag-Erling Smørgrav 	temporarily_use_uid(pw);
20780628bacSDag-Erling Smørgrav 
20880628bacSDag-Erling Smørgrav 	/* Allocate a buffer for the socket name, and format the name. */
209d4af9e69SDag-Erling Smørgrav 	auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX");
21080628bacSDag-Erling Smørgrav 
21180628bacSDag-Erling Smørgrav 	/* Create private directory for socket */
21280628bacSDag-Erling Smørgrav 	if (mkdtemp(auth_sock_dir) == NULL) {
21319261079SEd Maste 		ssh_packet_send_debug(ssh, "Agent forwarding disabled: "
21480628bacSDag-Erling Smørgrav 		    "mkdtemp() failed: %.100s", strerror(errno));
21580628bacSDag-Erling Smørgrav 		restore_uid();
216e4a9863fSDag-Erling Smørgrav 		free(auth_sock_dir);
21780628bacSDag-Erling Smørgrav 		auth_sock_dir = NULL;
218d4af9e69SDag-Erling Smørgrav 		goto authsock_err;
21980628bacSDag-Erling Smørgrav 	}
220d4af9e69SDag-Erling Smørgrav 
221d4af9e69SDag-Erling Smørgrav 	xasprintf(&auth_sock_name, "%s/agent.%ld",
22280628bacSDag-Erling Smørgrav 	    auth_sock_dir, (long) getpid());
22380628bacSDag-Erling Smørgrav 
224a0ee8cc6SDag-Erling Smørgrav 	/* Start a Unix listener on auth_sock_name. */
225a0ee8cc6SDag-Erling Smørgrav 	sock = unix_listener(auth_sock_name, SSH_LISTEN_BACKLOG, 0);
22680628bacSDag-Erling Smørgrav 
22780628bacSDag-Erling Smørgrav 	/* Restore the privileged uid. */
22880628bacSDag-Erling Smørgrav 	restore_uid();
22980628bacSDag-Erling Smørgrav 
230a0ee8cc6SDag-Erling Smørgrav 	/* Check for socket/bind/listen failure. */
231a0ee8cc6SDag-Erling Smørgrav 	if (sock < 0)
232d4af9e69SDag-Erling Smørgrav 		goto authsock_err;
23380628bacSDag-Erling Smørgrav 
23460c59fadSDag-Erling Smørgrav 	/* Allocate a channel for the authentication agent socket. */
235f374ba41SEd Maste 	nc = channel_new(ssh, "auth-listener",
23680628bacSDag-Erling Smørgrav 	    SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,
23780628bacSDag-Erling Smørgrav 	    CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
238cf2b5f3bSDag-Erling Smørgrav 	    0, "auth socket", 1);
239cce7d346SDag-Erling Smørgrav 	nc->path = xstrdup(auth_sock_name);
24080628bacSDag-Erling Smørgrav 	return 1;
241d4af9e69SDag-Erling Smørgrav 
242d4af9e69SDag-Erling Smørgrav  authsock_err:
243e4a9863fSDag-Erling Smørgrav 	free(auth_sock_name);
244d4af9e69SDag-Erling Smørgrav 	if (auth_sock_dir != NULL) {
24519261079SEd Maste 		temporarily_use_uid(pw);
246d4af9e69SDag-Erling Smørgrav 		rmdir(auth_sock_dir);
24719261079SEd Maste 		restore_uid();
248e4a9863fSDag-Erling Smørgrav 		free(auth_sock_dir);
249d4af9e69SDag-Erling Smørgrav 	}
250d4af9e69SDag-Erling Smørgrav 	if (sock != -1)
251d4af9e69SDag-Erling Smørgrav 		close(sock);
252d4af9e69SDag-Erling Smørgrav 	auth_sock_name = NULL;
253d4af9e69SDag-Erling Smørgrav 	auth_sock_dir = NULL;
254d4af9e69SDag-Erling Smørgrav 	return 0;
25580628bacSDag-Erling Smørgrav }
25680628bacSDag-Erling Smørgrav 
2571ec0d754SDag-Erling Smørgrav static void
display_loginmsg(void)2581ec0d754SDag-Erling Smørgrav display_loginmsg(void)
2591ec0d754SDag-Erling Smørgrav {
260190cef3dSDag-Erling Smørgrav 	int r;
261190cef3dSDag-Erling Smørgrav 
262190cef3dSDag-Erling Smørgrav 	if (sshbuf_len(loginmsg) == 0)
263190cef3dSDag-Erling Smørgrav 		return;
264190cef3dSDag-Erling Smørgrav 	if ((r = sshbuf_put_u8(loginmsg, 0)) != 0)
26519261079SEd Maste 		fatal_fr(r, "sshbuf_put_u8");
266190cef3dSDag-Erling Smørgrav 	printf("%s", (char *)sshbuf_ptr(loginmsg));
267190cef3dSDag-Erling Smørgrav 	sshbuf_reset(loginmsg);
2681ec0d754SDag-Erling Smørgrav }
26980628bacSDag-Erling Smørgrav 
2704f52dfbbSDag-Erling Smørgrav static void
prepare_auth_info_file(struct passwd * pw,struct sshbuf * info)2714f52dfbbSDag-Erling Smørgrav prepare_auth_info_file(struct passwd *pw, struct sshbuf *info)
2724f52dfbbSDag-Erling Smørgrav {
2734f52dfbbSDag-Erling Smørgrav 	int fd = -1, success = 0;
2744f52dfbbSDag-Erling Smørgrav 
2754f52dfbbSDag-Erling Smørgrav 	if (!options.expose_userauth_info || info == NULL)
2764f52dfbbSDag-Erling Smørgrav 		return;
2774f52dfbbSDag-Erling Smørgrav 
2784f52dfbbSDag-Erling Smørgrav 	temporarily_use_uid(pw);
2794f52dfbbSDag-Erling Smørgrav 	auth_info_file = xstrdup("/tmp/sshauth.XXXXXXXXXXXXXXX");
2804f52dfbbSDag-Erling Smørgrav 	if ((fd = mkstemp(auth_info_file)) == -1) {
28119261079SEd Maste 		error_f("mkstemp: %s", strerror(errno));
2824f52dfbbSDag-Erling Smørgrav 		goto out;
2834f52dfbbSDag-Erling Smørgrav 	}
2844f52dfbbSDag-Erling Smørgrav 	if (atomicio(vwrite, fd, sshbuf_mutable_ptr(info),
2854f52dfbbSDag-Erling Smørgrav 	    sshbuf_len(info)) != sshbuf_len(info)) {
28619261079SEd Maste 		error_f("write: %s", strerror(errno));
2874f52dfbbSDag-Erling Smørgrav 		goto out;
2884f52dfbbSDag-Erling Smørgrav 	}
2894f52dfbbSDag-Erling Smørgrav 	if (close(fd) != 0) {
29019261079SEd Maste 		error_f("close: %s", strerror(errno));
2914f52dfbbSDag-Erling Smørgrav 		goto out;
2924f52dfbbSDag-Erling Smørgrav 	}
2934f52dfbbSDag-Erling Smørgrav 	success = 1;
2944f52dfbbSDag-Erling Smørgrav  out:
2954f52dfbbSDag-Erling Smørgrav 	if (!success) {
2964f52dfbbSDag-Erling Smørgrav 		if (fd != -1)
2974f52dfbbSDag-Erling Smørgrav 			close(fd);
2984f52dfbbSDag-Erling Smørgrav 		free(auth_info_file);
2994f52dfbbSDag-Erling Smørgrav 		auth_info_file = NULL;
3004f52dfbbSDag-Erling Smørgrav 	}
3014f52dfbbSDag-Erling Smørgrav 	restore_uid();
3024f52dfbbSDag-Erling Smørgrav }
3034f52dfbbSDag-Erling Smørgrav 
30447dd1d1bSDag-Erling Smørgrav static void
set_fwdpermit_from_authopts(struct ssh * ssh,const struct sshauthopt * opts)305190cef3dSDag-Erling Smørgrav set_fwdpermit_from_authopts(struct ssh *ssh, const struct sshauthopt *opts)
30647dd1d1bSDag-Erling Smørgrav {
30747dd1d1bSDag-Erling Smørgrav 	char *tmp, *cp, *host;
30847dd1d1bSDag-Erling Smørgrav 	int port;
30947dd1d1bSDag-Erling Smørgrav 	size_t i;
31047dd1d1bSDag-Erling Smørgrav 
311190cef3dSDag-Erling Smørgrav 	if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0) {
312190cef3dSDag-Erling Smørgrav 		channel_clear_permission(ssh, FORWARD_USER, FORWARD_LOCAL);
31347dd1d1bSDag-Erling Smørgrav 		for (i = 0; i < auth_opts->npermitopen; i++) {
31447dd1d1bSDag-Erling Smørgrav 			tmp = cp = xstrdup(auth_opts->permitopen[i]);
31547dd1d1bSDag-Erling Smørgrav 			/* This shouldn't fail as it has already been checked */
3161323ec57SEd Maste 			if ((host = hpdelim2(&cp, NULL)) == NULL)
31719261079SEd Maste 				fatal_f("internal error: hpdelim");
31847dd1d1bSDag-Erling Smørgrav 			host = cleanhostname(host);
31947dd1d1bSDag-Erling Smørgrav 			if (cp == NULL || (port = permitopen_port(cp)) < 0)
32019261079SEd Maste 				fatal_f("internal error: permitopen port");
321190cef3dSDag-Erling Smørgrav 			channel_add_permission(ssh,
322190cef3dSDag-Erling Smørgrav 			    FORWARD_USER, FORWARD_LOCAL, host, port);
32347dd1d1bSDag-Erling Smørgrav 			free(tmp);
32447dd1d1bSDag-Erling Smørgrav 		}
32547dd1d1bSDag-Erling Smørgrav 	}
326190cef3dSDag-Erling Smørgrav 	if ((options.allow_tcp_forwarding & FORWARD_REMOTE) != 0) {
327190cef3dSDag-Erling Smørgrav 		channel_clear_permission(ssh, FORWARD_USER, FORWARD_REMOTE);
328190cef3dSDag-Erling Smørgrav 		for (i = 0; i < auth_opts->npermitlisten; i++) {
329190cef3dSDag-Erling Smørgrav 			tmp = cp = xstrdup(auth_opts->permitlisten[i]);
330190cef3dSDag-Erling Smørgrav 			/* This shouldn't fail as it has already been checked */
331190cef3dSDag-Erling Smørgrav 			if ((host = hpdelim(&cp)) == NULL)
33219261079SEd Maste 				fatal_f("internal error: hpdelim");
333190cef3dSDag-Erling Smørgrav 			host = cleanhostname(host);
334190cef3dSDag-Erling Smørgrav 			if (cp == NULL || (port = permitopen_port(cp)) < 0)
33519261079SEd Maste 				fatal_f("internal error: permitlisten port");
336190cef3dSDag-Erling Smørgrav 			channel_add_permission(ssh,
337190cef3dSDag-Erling Smørgrav 			    FORWARD_USER, FORWARD_REMOTE, host, port);
338190cef3dSDag-Erling Smørgrav 			free(tmp);
339190cef3dSDag-Erling Smørgrav 		}
340190cef3dSDag-Erling Smørgrav 	}
341190cef3dSDag-Erling Smørgrav }
34247dd1d1bSDag-Erling Smørgrav 
343ca3176e7SBrian Feldman void
do_authenticated(struct ssh * ssh,Authctxt * authctxt)3444f52dfbbSDag-Erling Smørgrav do_authenticated(struct ssh *ssh, Authctxt *authctxt)
345ca3176e7SBrian Feldman {
346e73e9afaSDag-Erling Smørgrav 	setproctitle("%s", authctxt->pw->pw_name);
347e73e9afaSDag-Erling Smørgrav 
34847dd1d1bSDag-Erling Smørgrav 	auth_log_authopts("active", auth_opts, 0);
34947dd1d1bSDag-Erling Smørgrav 
350ca3176e7SBrian Feldman 	/* setup the channel layer */
351a0ee8cc6SDag-Erling Smørgrav 	/* XXX - streamlocal? */
352190cef3dSDag-Erling Smørgrav 	set_fwdpermit_from_authopts(ssh, auth_opts);
353ca3176e7SBrian Feldman 
354190cef3dSDag-Erling Smørgrav 	if (!auth_opts->permit_port_forwarding_flag ||
355190cef3dSDag-Erling Smørgrav 	    options.disable_forwarding) {
356190cef3dSDag-Erling Smørgrav 		channel_disable_admin(ssh, FORWARD_LOCAL);
357190cef3dSDag-Erling Smørgrav 		channel_disable_admin(ssh, FORWARD_REMOTE);
358190cef3dSDag-Erling Smørgrav 	} else {
359190cef3dSDag-Erling Smørgrav 		if ((options.allow_tcp_forwarding & FORWARD_LOCAL) == 0)
360190cef3dSDag-Erling Smørgrav 			channel_disable_admin(ssh, FORWARD_LOCAL);
361190cef3dSDag-Erling Smørgrav 		else
362190cef3dSDag-Erling Smørgrav 			channel_permit_all(ssh, FORWARD_LOCAL);
363190cef3dSDag-Erling Smørgrav 		if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0)
364190cef3dSDag-Erling Smørgrav 			channel_disable_admin(ssh, FORWARD_REMOTE);
365190cef3dSDag-Erling Smørgrav 		else
366190cef3dSDag-Erling Smørgrav 			channel_permit_all(ssh, FORWARD_REMOTE);
367190cef3dSDag-Erling Smørgrav 	}
36819261079SEd Maste 	auth_debug_send(ssh);
369b15c8340SDag-Erling Smørgrav 
3704f52dfbbSDag-Erling Smørgrav 	prepare_auth_info_file(authctxt->pw, authctxt->session_info);
3714f52dfbbSDag-Erling Smørgrav 
3724f52dfbbSDag-Erling Smørgrav 	do_authenticated2(ssh, authctxt);
3734f52dfbbSDag-Erling Smørgrav 
3744f52dfbbSDag-Erling Smørgrav 	do_cleanup(ssh, authctxt);
375a04a10f8SKris Kennaway }
376a04a10f8SKris Kennaway 
377acc1a9efSDag-Erling Smørgrav /* Check untrusted xauth strings for metacharacters */
378acc1a9efSDag-Erling Smørgrav static int
xauth_valid_string(const char * s)379acc1a9efSDag-Erling Smørgrav xauth_valid_string(const char *s)
380acc1a9efSDag-Erling Smørgrav {
381acc1a9efSDag-Erling Smørgrav 	size_t i;
382acc1a9efSDag-Erling Smørgrav 
383acc1a9efSDag-Erling Smørgrav 	for (i = 0; s[i] != '\0'; i++) {
384acc1a9efSDag-Erling Smørgrav 		if (!isalnum((u_char)s[i]) &&
385acc1a9efSDag-Erling Smørgrav 		    s[i] != '.' && s[i] != ':' && s[i] != '/' &&
386acc1a9efSDag-Erling Smørgrav 		    s[i] != '-' && s[i] != '_')
387acc1a9efSDag-Erling Smørgrav 			return 0;
388acc1a9efSDag-Erling Smørgrav 	}
389acc1a9efSDag-Erling Smørgrav 	return 1;
390acc1a9efSDag-Erling Smørgrav }
391acc1a9efSDag-Erling Smørgrav 
392f7167e0eSDag-Erling Smørgrav #define USE_PIPES 1
393a04a10f8SKris Kennaway /*
394a04a10f8SKris Kennaway  * This is called to fork and execute a command when we have no tty.  This
395a04a10f8SKris Kennaway  * will call do_child from the child, and server_loop from the parent after
396a04a10f8SKris Kennaway  * setting up file descriptors and such.
397a04a10f8SKris Kennaway  */
398d4af9e69SDag-Erling Smørgrav int
do_exec_no_pty(struct ssh * ssh,Session * s,const char * command)3994f52dfbbSDag-Erling Smørgrav do_exec_no_pty(struct ssh *ssh, Session *s, const char *command)
400a04a10f8SKris Kennaway {
40180628bacSDag-Erling Smørgrav 	pid_t pid;
402a04a10f8SKris Kennaway #ifdef USE_PIPES
403a04a10f8SKris Kennaway 	int pin[2], pout[2], perr[2];
404d4af9e69SDag-Erling Smørgrav 
405e2f6069cSDag-Erling Smørgrav 	if (s == NULL)
406e2f6069cSDag-Erling Smørgrav 		fatal("do_exec_no_pty: no session");
407e2f6069cSDag-Erling Smørgrav 
408a04a10f8SKris Kennaway 	/* Allocate pipes for communicating with the program. */
40919261079SEd Maste 	if (pipe(pin) == -1) {
41019261079SEd Maste 		error_f("pipe in: %.100s", strerror(errno));
411d4af9e69SDag-Erling Smørgrav 		return -1;
412d4af9e69SDag-Erling Smørgrav 	}
41319261079SEd Maste 	if (pipe(pout) == -1) {
41419261079SEd Maste 		error_f("pipe out: %.100s", strerror(errno));
415d4af9e69SDag-Erling Smørgrav 		close(pin[0]);
416d4af9e69SDag-Erling Smørgrav 		close(pin[1]);
417d4af9e69SDag-Erling Smørgrav 		return -1;
418d4af9e69SDag-Erling Smørgrav 	}
41919261079SEd Maste 	if (pipe(perr) == -1) {
42019261079SEd Maste 		error_f("pipe err: %.100s", strerror(errno));
421d4af9e69SDag-Erling Smørgrav 		close(pin[0]);
422d4af9e69SDag-Erling Smørgrav 		close(pin[1]);
423d4af9e69SDag-Erling Smørgrav 		close(pout[0]);
424d4af9e69SDag-Erling Smørgrav 		close(pout[1]);
425d4af9e69SDag-Erling Smørgrav 		return -1;
426d4af9e69SDag-Erling Smørgrav 	}
427d4af9e69SDag-Erling Smørgrav #else
428a04a10f8SKris Kennaway 	int inout[2], err[2];
429d4af9e69SDag-Erling Smørgrav 
430e2f6069cSDag-Erling Smørgrav 	if (s == NULL)
431e2f6069cSDag-Erling Smørgrav 		fatal("do_exec_no_pty: no session");
432e2f6069cSDag-Erling Smørgrav 
433a04a10f8SKris Kennaway 	/* Uses socket pairs to communicate with the program. */
43419261079SEd Maste 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) {
43519261079SEd Maste 		error_f("socketpair #1: %.100s", strerror(errno));
436d4af9e69SDag-Erling Smørgrav 		return -1;
437d4af9e69SDag-Erling Smørgrav 	}
43819261079SEd Maste 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) == -1) {
43919261079SEd Maste 		error_f("socketpair #2: %.100s", strerror(errno));
440d4af9e69SDag-Erling Smørgrav 		close(inout[0]);
441d4af9e69SDag-Erling Smørgrav 		close(inout[1]);
442d4af9e69SDag-Erling Smørgrav 		return -1;
443d4af9e69SDag-Erling Smørgrav 	}
444d4af9e69SDag-Erling Smørgrav #endif
445d4af9e69SDag-Erling Smørgrav 
446a04a10f8SKris Kennaway 	session_proctitle(s);
447a04a10f8SKris Kennaway 
448a04a10f8SKris Kennaway 	/* Fork the child. */
449d4af9e69SDag-Erling Smørgrav 	switch ((pid = fork())) {
450d4af9e69SDag-Erling Smørgrav 	case -1:
45119261079SEd Maste 		error_f("fork: %.100s", strerror(errno));
452d4af9e69SDag-Erling Smørgrav #ifdef USE_PIPES
453d4af9e69SDag-Erling Smørgrav 		close(pin[0]);
454d4af9e69SDag-Erling Smørgrav 		close(pin[1]);
455d4af9e69SDag-Erling Smørgrav 		close(pout[0]);
456d4af9e69SDag-Erling Smørgrav 		close(pout[1]);
457d4af9e69SDag-Erling Smørgrav 		close(perr[0]);
458d4af9e69SDag-Erling Smørgrav 		close(perr[1]);
459d4af9e69SDag-Erling Smørgrav #else
460d4af9e69SDag-Erling Smørgrav 		close(inout[0]);
461d4af9e69SDag-Erling Smørgrav 		close(inout[1]);
462d4af9e69SDag-Erling Smørgrav 		close(err[0]);
463d4af9e69SDag-Erling Smørgrav 		close(err[1]);
464d4af9e69SDag-Erling Smørgrav #endif
465d4af9e69SDag-Erling Smørgrav 		return -1;
466d4af9e69SDag-Erling Smørgrav 	case 0:
4671ec0d754SDag-Erling Smørgrav 		is_child = 1;
468f388f5efSDag-Erling Smørgrav 
469a04a10f8SKris Kennaway 		/*
470a04a10f8SKris Kennaway 		 * Create a new session and process group since the 4.4BSD
471a04a10f8SKris Kennaway 		 * setlogin() affects the entire process group.
472a04a10f8SKris Kennaway 		 */
47319261079SEd Maste 		if (setsid() == -1)
474a04a10f8SKris Kennaway 			error("setsid failed: %.100s", strerror(errno));
475a04a10f8SKris Kennaway 
476a04a10f8SKris Kennaway #ifdef USE_PIPES
477a04a10f8SKris Kennaway 		/*
478a04a10f8SKris Kennaway 		 * Redirect stdin.  We close the parent side of the socket
479a04a10f8SKris Kennaway 		 * pair, and make the child side the standard input.
480a04a10f8SKris Kennaway 		 */
481a04a10f8SKris Kennaway 		close(pin[1]);
48219261079SEd Maste 		if (dup2(pin[0], 0) == -1)
483a04a10f8SKris Kennaway 			perror("dup2 stdin");
484a04a10f8SKris Kennaway 		close(pin[0]);
485a04a10f8SKris Kennaway 
486a04a10f8SKris Kennaway 		/* Redirect stdout. */
487a04a10f8SKris Kennaway 		close(pout[0]);
48819261079SEd Maste 		if (dup2(pout[1], 1) == -1)
489a04a10f8SKris Kennaway 			perror("dup2 stdout");
490a04a10f8SKris Kennaway 		close(pout[1]);
491a04a10f8SKris Kennaway 
492a04a10f8SKris Kennaway 		/* Redirect stderr. */
493a04a10f8SKris Kennaway 		close(perr[0]);
49419261079SEd Maste 		if (dup2(perr[1], 2) == -1)
495a04a10f8SKris Kennaway 			perror("dup2 stderr");
496a04a10f8SKris Kennaway 		close(perr[1]);
497d4af9e69SDag-Erling Smørgrav #else
498a04a10f8SKris Kennaway 		/*
499a04a10f8SKris Kennaway 		 * Redirect stdin, stdout, and stderr.  Stdin and stdout will
500a04a10f8SKris Kennaway 		 * use the same socket, as some programs (particularly rdist)
501a04a10f8SKris Kennaway 		 * seem to depend on it.
502a04a10f8SKris Kennaway 		 */
503a04a10f8SKris Kennaway 		close(inout[1]);
504a04a10f8SKris Kennaway 		close(err[1]);
50519261079SEd Maste 		if (dup2(inout[0], 0) == -1)	/* stdin */
506a04a10f8SKris Kennaway 			perror("dup2 stdin");
50719261079SEd Maste 		if (dup2(inout[0], 1) == -1)	/* stdout (same as stdin) */
508a04a10f8SKris Kennaway 			perror("dup2 stdout");
509d4af9e69SDag-Erling Smørgrav 		close(inout[0]);
51019261079SEd Maste 		if (dup2(err[0], 2) == -1)	/* stderr */
511a04a10f8SKris Kennaway 			perror("dup2 stderr");
512d4af9e69SDag-Erling Smørgrav 		close(err[0]);
513d4af9e69SDag-Erling Smørgrav #endif
514d4af9e69SDag-Erling Smørgrav 
515a04a10f8SKris Kennaway 		/* Do processing for the child (exec command etc). */
5164f52dfbbSDag-Erling Smørgrav 		do_child(ssh, s, command);
517a04a10f8SKris Kennaway 		/* NOTREACHED */
518d4af9e69SDag-Erling Smørgrav 	default:
519d4af9e69SDag-Erling Smørgrav 		break;
520a04a10f8SKris Kennaway 	}
521d4af9e69SDag-Erling Smørgrav 
522989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN
523989dd127SDag-Erling Smørgrav 	cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
524989dd127SDag-Erling Smørgrav #endif
525d4af9e69SDag-Erling Smørgrav 
526a04a10f8SKris Kennaway 	s->pid = pid;
527ca3176e7SBrian Feldman 	/* Set interactive/non-interactive mode. */
52819261079SEd Maste 	ssh_packet_set_interactive(ssh, s->display != NULL,
5294a421b63SDag-Erling Smørgrav 	    options.ip_qos_interactive, options.ip_qos_bulk);
530d4af9e69SDag-Erling Smørgrav 
531d4af9e69SDag-Erling Smørgrav 	/*
532d4af9e69SDag-Erling Smørgrav 	 * Clear loginmsg, since it's the child's responsibility to display
533d4af9e69SDag-Erling Smørgrav 	 * it to the user, otherwise multiple sessions may accumulate
534d4af9e69SDag-Erling Smørgrav 	 * multiple copies of the login messages.
535d4af9e69SDag-Erling Smørgrav 	 */
536190cef3dSDag-Erling Smørgrav 	sshbuf_reset(loginmsg);
537d4af9e69SDag-Erling Smørgrav 
538a04a10f8SKris Kennaway #ifdef USE_PIPES
539a04a10f8SKris Kennaway 	/* We are the parent.  Close the child sides of the pipes. */
540a04a10f8SKris Kennaway 	close(pin[0]);
541a04a10f8SKris Kennaway 	close(pout[1]);
542a04a10f8SKris Kennaway 	close(perr[1]);
543a04a10f8SKris Kennaway 
5444f52dfbbSDag-Erling Smørgrav 	session_set_fds(ssh, s, pin[1], pout[0], perr[0],
545e2f6069cSDag-Erling Smørgrav 	    s->is_subsystem, 0);
546d4af9e69SDag-Erling Smørgrav #else
547a04a10f8SKris Kennaway 	/* We are the parent.  Close the child sides of the socket pairs. */
548a04a10f8SKris Kennaway 	close(inout[0]);
549a04a10f8SKris Kennaway 	close(err[0]);
550a04a10f8SKris Kennaway 
551a04a10f8SKris Kennaway 	/*
552a04a10f8SKris Kennaway 	 * Enter the interactive session.  Note: server_loop must be able to
553a04a10f8SKris Kennaway 	 * handle the case that fdin and fdout are the same.
554a04a10f8SKris Kennaway 	 */
55519261079SEd Maste 	session_set_fds(ssh, s, inout[1], inout[1], err[1],
556e2f6069cSDag-Erling Smørgrav 	    s->is_subsystem, 0);
557d4af9e69SDag-Erling Smørgrav #endif
558d4af9e69SDag-Erling Smørgrav 	return 0;
559a04a10f8SKris Kennaway }
560a04a10f8SKris Kennaway 
561a04a10f8SKris Kennaway /*
562a04a10f8SKris Kennaway  * This is called to fork and execute a command when we have a tty.  This
563a04a10f8SKris Kennaway  * will call do_child from the child, and server_loop from the parent after
564a04a10f8SKris Kennaway  * setting up file descriptors, controlling tty, updating wtmp, utmp,
565a04a10f8SKris Kennaway  * lastlog, and other such operations.
566a04a10f8SKris Kennaway  */
567d4af9e69SDag-Erling Smørgrav int
do_exec_pty(struct ssh * ssh,Session * s,const char * command)5684f52dfbbSDag-Erling Smørgrav do_exec_pty(struct ssh *ssh, Session *s, const char *command)
569a04a10f8SKris Kennaway {
570a04a10f8SKris Kennaway 	int fdout, ptyfd, ttyfd, ptymaster;
571a04a10f8SKris Kennaway 	pid_t pid;
572a04a10f8SKris Kennaway 
573a04a10f8SKris Kennaway 	if (s == NULL)
574a04a10f8SKris Kennaway 		fatal("do_exec_pty: no session");
575a04a10f8SKris Kennaway 	ptyfd = s->ptyfd;
576a04a10f8SKris Kennaway 	ttyfd = s->ttyfd;
577a04a10f8SKris Kennaway 
578d4af9e69SDag-Erling Smørgrav 	/*
579d4af9e69SDag-Erling Smørgrav 	 * Create another descriptor of the pty master side for use as the
580d4af9e69SDag-Erling Smørgrav 	 * standard input.  We could use the original descriptor, but this
581d4af9e69SDag-Erling Smørgrav 	 * simplifies code in server_loop.  The descriptor is bidirectional.
582d4af9e69SDag-Erling Smørgrav 	 * Do this before forking (and cleanup in the child) so as to
583d4af9e69SDag-Erling Smørgrav 	 * detect and gracefully fail out-of-fd conditions.
584d4af9e69SDag-Erling Smørgrav 	 */
58519261079SEd Maste 	if ((fdout = dup(ptyfd)) == -1) {
58619261079SEd Maste 		error_f("dup #1: %s", strerror(errno));
587d4af9e69SDag-Erling Smørgrav 		close(ttyfd);
588d4af9e69SDag-Erling Smørgrav 		close(ptyfd);
589d4af9e69SDag-Erling Smørgrav 		return -1;
590cf2b5f3bSDag-Erling Smørgrav 	}
591d4af9e69SDag-Erling Smørgrav 	/* we keep a reference to the pty master */
59219261079SEd Maste 	if ((ptymaster = dup(ptyfd)) == -1) {
59319261079SEd Maste 		error_f("dup #2: %s", strerror(errno));
594d4af9e69SDag-Erling Smørgrav 		close(ttyfd);
595d4af9e69SDag-Erling Smørgrav 		close(ptyfd);
596d4af9e69SDag-Erling Smørgrav 		close(fdout);
597d4af9e69SDag-Erling Smørgrav 		return -1;
598d4af9e69SDag-Erling Smørgrav 	}
59909958426SBrian Feldman 
600a04a10f8SKris Kennaway 	/* Fork the child. */
601d4af9e69SDag-Erling Smørgrav 	switch ((pid = fork())) {
602d4af9e69SDag-Erling Smørgrav 	case -1:
60319261079SEd Maste 		error_f("fork: %.100s", strerror(errno));
604d4af9e69SDag-Erling Smørgrav 		close(fdout);
605d4af9e69SDag-Erling Smørgrav 		close(ptymaster);
606d4af9e69SDag-Erling Smørgrav 		close(ttyfd);
607d4af9e69SDag-Erling Smørgrav 		close(ptyfd);
608d4af9e69SDag-Erling Smørgrav 		return -1;
609d4af9e69SDag-Erling Smørgrav 	case 0:
6101ec0d754SDag-Erling Smørgrav 		is_child = 1;
611af12a3e7SDag-Erling Smørgrav 
612d4af9e69SDag-Erling Smørgrav 		close(fdout);
613d4af9e69SDag-Erling Smørgrav 		close(ptymaster);
614d4af9e69SDag-Erling Smørgrav 
615a04a10f8SKris Kennaway 		/* Close the master side of the pseudo tty. */
616a04a10f8SKris Kennaway 		close(ptyfd);
617a04a10f8SKris Kennaway 
618a04a10f8SKris Kennaway 		/* Make the pseudo tty our controlling tty. */
619a04a10f8SKris Kennaway 		pty_make_controlling_tty(&ttyfd, s->tty);
620a04a10f8SKris Kennaway 
621af12a3e7SDag-Erling Smørgrav 		/* Redirect stdin/stdout/stderr from the pseudo tty. */
62219261079SEd Maste 		if (dup2(ttyfd, 0) == -1)
623af12a3e7SDag-Erling Smørgrav 			error("dup2 stdin: %s", strerror(errno));
62419261079SEd Maste 		if (dup2(ttyfd, 1) == -1)
625af12a3e7SDag-Erling Smørgrav 			error("dup2 stdout: %s", strerror(errno));
62619261079SEd Maste 		if (dup2(ttyfd, 2) == -1)
627af12a3e7SDag-Erling Smørgrav 			error("dup2 stderr: %s", strerror(errno));
628a04a10f8SKris Kennaway 
629a04a10f8SKris Kennaway 		/* Close the extra descriptor for the pseudo tty. */
630a04a10f8SKris Kennaway 		close(ttyfd);
631a04a10f8SKris Kennaway 
632c2d3a559SKris Kennaway 		/* record login, etc. similar to login(1) */
633ca86bcf2SDag-Erling Smørgrav #ifndef HAVE_OSF_SIA
6344f52dfbbSDag-Erling Smørgrav 		do_login(ssh, s, command);
635989dd127SDag-Erling Smørgrav #endif
636d4af9e69SDag-Erling Smørgrav 		/*
637d4af9e69SDag-Erling Smørgrav 		 * Do common processing for the child, such as execing
638d4af9e69SDag-Erling Smørgrav 		 * the command.
639d4af9e69SDag-Erling Smørgrav 		 */
6404f52dfbbSDag-Erling Smørgrav 		do_child(ssh, s, command);
641a04a10f8SKris Kennaway 		/* NOTREACHED */
642d4af9e69SDag-Erling Smørgrav 	default:
643d4af9e69SDag-Erling Smørgrav 		break;
644a04a10f8SKris Kennaway 	}
645d4af9e69SDag-Erling Smørgrav 
646989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN
647989dd127SDag-Erling Smørgrav 	cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
648989dd127SDag-Erling Smørgrav #endif
649d4af9e69SDag-Erling Smørgrav 
650a04a10f8SKris Kennaway 	s->pid = pid;
651a04a10f8SKris Kennaway 
652a04a10f8SKris Kennaway 	/* Parent.  Close the slave side of the pseudo tty. */
653a04a10f8SKris Kennaway 	close(ttyfd);
654a04a10f8SKris Kennaway 
655a04a10f8SKris Kennaway 	/* Enter interactive session. */
656d4af9e69SDag-Erling Smørgrav 	s->ptymaster = ptymaster;
65719261079SEd Maste 	ssh_packet_set_interactive(ssh, 1,
6584a421b63SDag-Erling Smørgrav 	    options.ip_qos_interactive, options.ip_qos_bulk);
6594f52dfbbSDag-Erling Smørgrav 	session_set_fds(ssh, s, ptyfd, fdout, -1, 1, 1);
660d4af9e69SDag-Erling Smørgrav 	return 0;
661a04a10f8SKris Kennaway }
662a04a10f8SKris Kennaway 
663af12a3e7SDag-Erling Smørgrav /*
664af12a3e7SDag-Erling Smørgrav  * This is called to fork and execute a command.  If another command is
665af12a3e7SDag-Erling Smørgrav  * to be forced, execute that instead.
666af12a3e7SDag-Erling Smørgrav  */
667d4af9e69SDag-Erling Smørgrav int
do_exec(struct ssh * ssh,Session * s,const char * command)6684f52dfbbSDag-Erling Smørgrav do_exec(struct ssh *ssh, Session *s, const char *command)
669af12a3e7SDag-Erling Smørgrav {
670d4af9e69SDag-Erling Smørgrav 	int ret;
671acc1a9efSDag-Erling Smørgrav 	const char *forced = NULL, *tty = NULL;
672acc1a9efSDag-Erling Smørgrav 	char session_type[1024];
673d4af9e69SDag-Erling Smørgrav 
674333ee039SDag-Erling Smørgrav 	if (options.adm_forced_command) {
675333ee039SDag-Erling Smørgrav 		original_command = command;
676333ee039SDag-Erling Smørgrav 		command = options.adm_forced_command;
677f7167e0eSDag-Erling Smørgrav 		forced = "(config)";
67847dd1d1bSDag-Erling Smørgrav 	} else if (auth_opts->force_command != NULL) {
679af12a3e7SDag-Erling Smørgrav 		original_command = command;
68047dd1d1bSDag-Erling Smørgrav 		command = auth_opts->force_command;
681f7167e0eSDag-Erling Smørgrav 		forced = "(key-option)";
682f7167e0eSDag-Erling Smørgrav 	}
6832f513db7SEd Maste 	s->forced = 0;
684f7167e0eSDag-Erling Smørgrav 	if (forced != NULL) {
6852f513db7SEd Maste 		s->forced = 1;
686b15c8340SDag-Erling Smørgrav 		if (IS_INTERNAL_SFTP(command)) {
687b15c8340SDag-Erling Smørgrav 			s->is_subsystem = s->is_subsystem ?
688b15c8340SDag-Erling Smørgrav 			    SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR;
689b15c8340SDag-Erling Smørgrav 		} else if (s->is_subsystem)
690d4af9e69SDag-Erling Smørgrav 			s->is_subsystem = SUBSYSTEM_EXT;
691f7167e0eSDag-Erling Smørgrav 		snprintf(session_type, sizeof(session_type),
692f7167e0eSDag-Erling Smørgrav 		    "forced-command %s '%.900s'", forced, command);
693f7167e0eSDag-Erling Smørgrav 	} else if (s->is_subsystem) {
694f7167e0eSDag-Erling Smørgrav 		snprintf(session_type, sizeof(session_type),
695f7167e0eSDag-Erling Smørgrav 		    "subsystem '%.900s'", s->subsys);
696f7167e0eSDag-Erling Smørgrav 	} else if (command == NULL) {
697f7167e0eSDag-Erling Smørgrav 		snprintf(session_type, sizeof(session_type), "shell");
698f7167e0eSDag-Erling Smørgrav 	} else {
699f7167e0eSDag-Erling Smørgrav 		/* NB. we don't log unforced commands to preserve privacy */
700f7167e0eSDag-Erling Smørgrav 		snprintf(session_type, sizeof(session_type), "command");
701af12a3e7SDag-Erling Smørgrav 	}
702af12a3e7SDag-Erling Smørgrav 
703f7167e0eSDag-Erling Smørgrav 	if (s->ttyfd != -1) {
704f7167e0eSDag-Erling Smørgrav 		tty = s->tty;
705f7167e0eSDag-Erling Smørgrav 		if (strncmp(tty, "/dev/", 5) == 0)
706f7167e0eSDag-Erling Smørgrav 			tty += 5;
707f7167e0eSDag-Erling Smørgrav 	}
708f7167e0eSDag-Erling Smørgrav 
709acc1a9efSDag-Erling Smørgrav 	verbose("Starting session: %s%s%s for %s from %.200s port %d id %d",
710f7167e0eSDag-Erling Smørgrav 	    session_type,
711f7167e0eSDag-Erling Smørgrav 	    tty == NULL ? "" : " on ",
712f7167e0eSDag-Erling Smørgrav 	    tty == NULL ? "" : tty,
713f7167e0eSDag-Erling Smørgrav 	    s->pw->pw_name,
714076ad2f8SDag-Erling Smørgrav 	    ssh_remote_ipaddr(ssh),
715076ad2f8SDag-Erling Smørgrav 	    ssh_remote_port(ssh),
716acc1a9efSDag-Erling Smørgrav 	    s->self);
717f7167e0eSDag-Erling Smørgrav 
718aa49c926SDag-Erling Smørgrav #ifdef SSH_AUDIT_EVENTS
719aa49c926SDag-Erling Smørgrav 	if (command != NULL)
7200fdf8faeSEd Maste 		mm_audit_run_command(command);
721aa49c926SDag-Erling Smørgrav 	else if (s->ttyfd == -1) {
722aa49c926SDag-Erling Smørgrav 		char *shell = s->pw->pw_shell;
723aa49c926SDag-Erling Smørgrav 
724aa49c926SDag-Erling Smørgrav 		if (shell[0] == '\0')	/* empty shell means /bin/sh */
725aa49c926SDag-Erling Smørgrav 			shell =_PATH_BSHELL;
7260fdf8faeSEd Maste 		mm_audit_run_command(shell);
727cf2b5f3bSDag-Erling Smørgrav 	}
728cf2b5f3bSDag-Erling Smørgrav #endif
729af12a3e7SDag-Erling Smørgrav 	if (s->ttyfd != -1)
7304f52dfbbSDag-Erling Smørgrav 		ret = do_exec_pty(ssh, s, command);
731af12a3e7SDag-Erling Smørgrav 	else
7324f52dfbbSDag-Erling Smørgrav 		ret = do_exec_no_pty(ssh, s, command);
733af12a3e7SDag-Erling Smørgrav 
734af12a3e7SDag-Erling Smørgrav 	original_command = NULL;
735af12a3e7SDag-Erling Smørgrav 
73621e764dfSDag-Erling Smørgrav 	/*
73721e764dfSDag-Erling Smørgrav 	 * Clear loginmsg: it's the child's responsibility to display
73821e764dfSDag-Erling Smørgrav 	 * it to the user, otherwise multiple sessions may accumulate
73921e764dfSDag-Erling Smørgrav 	 * multiple copies of the login messages.
74021e764dfSDag-Erling Smørgrav 	 */
741190cef3dSDag-Erling Smørgrav 	sshbuf_reset(loginmsg);
742d4af9e69SDag-Erling Smørgrav 
743d4af9e69SDag-Erling Smørgrav 	return ret;
74421e764dfSDag-Erling Smørgrav }
745af12a3e7SDag-Erling Smørgrav 
746c2d3a559SKris Kennaway /* administrative, login(1)-like work */
747ca3176e7SBrian Feldman void
do_login(struct ssh * ssh,Session * s,const char * command)7484f52dfbbSDag-Erling Smørgrav do_login(struct ssh *ssh, Session *s, const char *command)
749c2d3a559SKris Kennaway {
750c2d3a559SKris Kennaway 	socklen_t fromlen;
751c2d3a559SKris Kennaway 	struct sockaddr_storage from;
752c2d3a559SKris Kennaway 
753c2d3a559SKris Kennaway 	/*
754c2d3a559SKris Kennaway 	 * Get IP address of client. If the connection is not a socket, let
755c2d3a559SKris Kennaway 	 * the address be 0.0.0.0.
756c2d3a559SKris Kennaway 	 */
757c2d3a559SKris Kennaway 	memset(&from, 0, sizeof(from));
758c2d3a559SKris Kennaway 	fromlen = sizeof(from);
75919261079SEd Maste 	if (ssh_packet_connection_is_on_socket(ssh)) {
76019261079SEd Maste 		if (getpeername(ssh_packet_get_connection_in(ssh),
76119261079SEd Maste 		    (struct sockaddr *)&from, &fromlen) == -1) {
762c2d3a559SKris Kennaway 			debug("getpeername: %.100s", strerror(errno));
7631ec0d754SDag-Erling Smørgrav 			cleanup_exit(255);
764c2d3a559SKris Kennaway 		}
765c2d3a559SKris Kennaway 	}
766c2d3a559SKris Kennaway 
767989dd127SDag-Erling Smørgrav 	if (check_quietlogin(s, command))
768989dd127SDag-Erling Smørgrav 		return;
769989dd127SDag-Erling Smørgrav 
7701ec0d754SDag-Erling Smørgrav 	display_loginmsg();
771f388f5efSDag-Erling Smørgrav 
772ca3176e7SBrian Feldman 	do_motd();
773ca3176e7SBrian Feldman }
774ca3176e7SBrian Feldman 
775ca3176e7SBrian Feldman /*
776ca3176e7SBrian Feldman  * Display the message of the day.
777ca3176e7SBrian Feldman  */
778ca3176e7SBrian Feldman void
do_motd(void)779ca3176e7SBrian Feldman do_motd(void)
780ca3176e7SBrian Feldman {
781ca3176e7SBrian Feldman 	FILE *f;
782ca3176e7SBrian Feldman 	char buf[256];
783ca3176e7SBrian Feldman 
784ca3176e7SBrian Feldman 	if (options.print_motd) {
785c2d3a559SKris Kennaway #ifdef HAVE_LOGIN_CAP
786c2d3a559SKris Kennaway 		f = fopen(login_getcapstr(lc, "welcome", "/etc/motd",
787c2d3a559SKris Kennaway 		    "/etc/motd"), "r");
788af12a3e7SDag-Erling Smørgrav #else
789c2d3a559SKris Kennaway 		f = fopen("/etc/motd", "r");
790af12a3e7SDag-Erling Smørgrav #endif
791c2d3a559SKris Kennaway 		if (f) {
792c2d3a559SKris Kennaway 			while (fgets(buf, sizeof(buf), f))
793c2d3a559SKris Kennaway 				fputs(buf, stdout);
794c2d3a559SKris Kennaway 			fclose(f);
795c2d3a559SKris Kennaway 		}
796c2d3a559SKris Kennaway 	}
797ca3176e7SBrian Feldman }
798c2d3a559SKris Kennaway 
799af12a3e7SDag-Erling Smørgrav 
800ca3176e7SBrian Feldman /*
801ca3176e7SBrian Feldman  * Check for quiet login, either .hushlogin or command given.
802ca3176e7SBrian Feldman  */
803ca3176e7SBrian Feldman int
check_quietlogin(Session * s,const char * command)804ca3176e7SBrian Feldman check_quietlogin(Session *s, const char *command)
805ca3176e7SBrian Feldman {
806ca3176e7SBrian Feldman 	char buf[256];
807ca3176e7SBrian Feldman 	struct passwd *pw = s->pw;
808ca3176e7SBrian Feldman 	struct stat st;
809ca3176e7SBrian Feldman 
810ca3176e7SBrian Feldman 	/* Return 1 if .hushlogin exists or a command given. */
811ca3176e7SBrian Feldman 	if (command != NULL)
812ca3176e7SBrian Feldman 		return 1;
813ca3176e7SBrian Feldman 	snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir);
814c2d3a559SKris Kennaway #ifdef HAVE_LOGIN_CAP
815ca3176e7SBrian Feldman 	if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0)
816ca3176e7SBrian Feldman 		return 1;
817ca3176e7SBrian Feldman #else
818ca3176e7SBrian Feldman 	if (stat(buf, &st) >= 0)
819ca3176e7SBrian Feldman 		return 1;
820ca3176e7SBrian Feldman #endif
821ca3176e7SBrian Feldman 	return 0;
822c2d3a559SKris Kennaway }
823c2d3a559SKris Kennaway 
824a04a10f8SKris Kennaway /*
825a04a10f8SKris Kennaway  * Reads environment variables from the given file and adds/overrides them
826a04a10f8SKris Kennaway  * into the environment.  If the file does not exist, this does nothing.
827a04a10f8SKris Kennaway  * Otherwise, it must consist of empty lines, comments (line starts with '#')
828a04a10f8SKris Kennaway  * and assignments of the form name=value.  No other forms are allowed.
82919261079SEd Maste  * If allowlist is not NULL, then it is interpreted as a pattern list and
830190cef3dSDag-Erling Smørgrav  * only variable names that match it will be accepted.
831a04a10f8SKris Kennaway  */
832af12a3e7SDag-Erling Smørgrav static void
read_environment_file(char *** env,u_int * envsize,const char * filename,const char * allowlist)833ca3176e7SBrian Feldman read_environment_file(char ***env, u_int *envsize,
83419261079SEd Maste 	const char *filename, const char *allowlist)
835a04a10f8SKris Kennaway {
836a04a10f8SKris Kennaway 	FILE *f;
837190cef3dSDag-Erling Smørgrav 	char *line = NULL, *cp, *value;
838190cef3dSDag-Erling Smørgrav 	size_t linesize = 0;
839a82e551fSDag-Erling Smørgrav 	u_int lineno = 0;
840a04a10f8SKris Kennaway 
841a04a10f8SKris Kennaway 	f = fopen(filename, "r");
842a04a10f8SKris Kennaway 	if (!f)
843a04a10f8SKris Kennaway 		return;
844a04a10f8SKris Kennaway 
845190cef3dSDag-Erling Smørgrav 	while (getline(&line, &linesize, f) != -1) {
846a82e551fSDag-Erling Smørgrav 		if (++lineno > 1000)
847a82e551fSDag-Erling Smørgrav 			fatal("Too many lines in environment file %s", filename);
848190cef3dSDag-Erling Smørgrav 		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
849a04a10f8SKris Kennaway 			;
850a04a10f8SKris Kennaway 		if (!*cp || *cp == '#' || *cp == '\n')
851a04a10f8SKris Kennaway 			continue;
852d4af9e69SDag-Erling Smørgrav 
853d4af9e69SDag-Erling Smørgrav 		cp[strcspn(cp, "\n")] = '\0';
854d4af9e69SDag-Erling Smørgrav 
855a04a10f8SKris Kennaway 		value = strchr(cp, '=');
856a04a10f8SKris Kennaway 		if (value == NULL) {
857a82e551fSDag-Erling Smørgrav 			fprintf(stderr, "Bad line %u in %.100s\n", lineno,
858a82e551fSDag-Erling Smørgrav 			    filename);
859a04a10f8SKris Kennaway 			continue;
860a04a10f8SKris Kennaway 		}
861db1cb46cSKris Kennaway 		/*
862db1cb46cSKris Kennaway 		 * Replace the equals sign by nul, and advance value to
863db1cb46cSKris Kennaway 		 * the value string.
864db1cb46cSKris Kennaway 		 */
865a04a10f8SKris Kennaway 		*value = '\0';
866a04a10f8SKris Kennaway 		value++;
86719261079SEd Maste 		if (allowlist != NULL &&
86819261079SEd Maste 		    match_pattern_list(cp, allowlist, 0) != 1)
869190cef3dSDag-Erling Smørgrav 			continue;
870a04a10f8SKris Kennaway 		child_set_env(env, envsize, cp, value);
871a04a10f8SKris Kennaway 	}
872190cef3dSDag-Erling Smørgrav 	free(line);
873a04a10f8SKris Kennaway 	fclose(f);
874a04a10f8SKris Kennaway }
875a04a10f8SKris Kennaway 
876cf2b5f3bSDag-Erling Smørgrav #ifdef HAVE_ETC_DEFAULT_LOGIN
877cf2b5f3bSDag-Erling Smørgrav /*
878cf2b5f3bSDag-Erling Smørgrav  * Return named variable from specified environment, or NULL if not present.
879cf2b5f3bSDag-Erling Smørgrav  */
880cf2b5f3bSDag-Erling Smørgrav static char *
child_get_env(char ** env,const char * name)881cf2b5f3bSDag-Erling Smørgrav child_get_env(char **env, const char *name)
882cf2b5f3bSDag-Erling Smørgrav {
883cf2b5f3bSDag-Erling Smørgrav 	int i;
884cf2b5f3bSDag-Erling Smørgrav 	size_t len;
885cf2b5f3bSDag-Erling Smørgrav 
886cf2b5f3bSDag-Erling Smørgrav 	len = strlen(name);
887cf2b5f3bSDag-Erling Smørgrav 	for (i=0; env[i] != NULL; i++)
888cf2b5f3bSDag-Erling Smørgrav 		if (strncmp(name, env[i], len) == 0 && env[i][len] == '=')
889cf2b5f3bSDag-Erling Smørgrav 			return(env[i] + len + 1);
890cf2b5f3bSDag-Erling Smørgrav 	return NULL;
891cf2b5f3bSDag-Erling Smørgrav }
892cf2b5f3bSDag-Erling Smørgrav 
893cf2b5f3bSDag-Erling Smørgrav /*
894cf2b5f3bSDag-Erling Smørgrav  * Read /etc/default/login.
895cf2b5f3bSDag-Erling Smørgrav  * We pick up the PATH (or SUPATH for root) and UMASK.
896cf2b5f3bSDag-Erling Smørgrav  */
897cf2b5f3bSDag-Erling Smørgrav static void
read_etc_default_login(char *** env,u_int * envsize,uid_t uid)898cf2b5f3bSDag-Erling Smørgrav read_etc_default_login(char ***env, u_int *envsize, uid_t uid)
899cf2b5f3bSDag-Erling Smørgrav {
900cf2b5f3bSDag-Erling Smørgrav 	char **tmpenv = NULL, *var;
901cf2b5f3bSDag-Erling Smørgrav 	u_int i, tmpenvsize = 0;
9021ec0d754SDag-Erling Smørgrav 	u_long mask;
903cf2b5f3bSDag-Erling Smørgrav 
904cf2b5f3bSDag-Erling Smørgrav 	/*
905cf2b5f3bSDag-Erling Smørgrav 	 * We don't want to copy the whole file to the child's environment,
906cf2b5f3bSDag-Erling Smørgrav 	 * so we use a temporary environment and copy the variables we're
907cf2b5f3bSDag-Erling Smørgrav 	 * interested in.
908cf2b5f3bSDag-Erling Smørgrav 	 */
909190cef3dSDag-Erling Smørgrav 	read_environment_file(&tmpenv, &tmpenvsize, "/etc/default/login",
91019261079SEd Maste 	    options.permit_user_env_allowlist);
911cf2b5f3bSDag-Erling Smørgrav 
912cf2b5f3bSDag-Erling Smørgrav 	if (tmpenv == NULL)
913cf2b5f3bSDag-Erling Smørgrav 		return;
914cf2b5f3bSDag-Erling Smørgrav 
915cf2b5f3bSDag-Erling Smørgrav 	if (uid == 0)
916cf2b5f3bSDag-Erling Smørgrav 		var = child_get_env(tmpenv, "SUPATH");
917cf2b5f3bSDag-Erling Smørgrav 	else
918cf2b5f3bSDag-Erling Smørgrav 		var = child_get_env(tmpenv, "PATH");
919cf2b5f3bSDag-Erling Smørgrav 	if (var != NULL)
920cf2b5f3bSDag-Erling Smørgrav 		child_set_env(env, envsize, "PATH", var);
921cf2b5f3bSDag-Erling Smørgrav 
922cf2b5f3bSDag-Erling Smørgrav 	if ((var = child_get_env(tmpenv, "UMASK")) != NULL)
923cf2b5f3bSDag-Erling Smørgrav 		if (sscanf(var, "%5lo", &mask) == 1)
9241ec0d754SDag-Erling Smørgrav 			umask((mode_t)mask);
925cf2b5f3bSDag-Erling Smørgrav 
926cf2b5f3bSDag-Erling Smørgrav 	for (i = 0; tmpenv[i] != NULL; i++)
927e4a9863fSDag-Erling Smørgrav 		free(tmpenv[i]);
928e4a9863fSDag-Erling Smørgrav 	free(tmpenv);
929cf2b5f3bSDag-Erling Smørgrav }
930cf2b5f3bSDag-Erling Smørgrav #endif /* HAVE_ETC_DEFAULT_LOGIN */
931cf2b5f3bSDag-Erling Smørgrav 
93219261079SEd Maste #if defined(USE_PAM) || defined(HAVE_CYGWIN)
9334f52dfbbSDag-Erling Smørgrav static void
copy_environment_denylist(char ** source,char *** env,u_int * envsize,const char * denylist)93419261079SEd Maste copy_environment_denylist(char **source, char ***env, u_int *envsize,
93519261079SEd Maste     const char *denylist)
93609958426SBrian Feldman {
937989dd127SDag-Erling Smørgrav 	char *var_name, *var_val;
93809958426SBrian Feldman 	int i;
93909958426SBrian Feldman 
940989dd127SDag-Erling Smørgrav 	if (source == NULL)
94109958426SBrian Feldman 		return;
94209958426SBrian Feldman 
943989dd127SDag-Erling Smørgrav 	for(i = 0; source[i] != NULL; i++) {
944989dd127SDag-Erling Smørgrav 		var_name = xstrdup(source[i]);
945989dd127SDag-Erling Smørgrav 		if ((var_val = strstr(var_name, "=")) == NULL) {
946e4a9863fSDag-Erling Smørgrav 			free(var_name);
94709958426SBrian Feldman 			continue;
948989dd127SDag-Erling Smørgrav 		}
949989dd127SDag-Erling Smørgrav 		*var_val++ = '\0';
95009958426SBrian Feldman 
95119261079SEd Maste 		if (denylist == NULL ||
95219261079SEd Maste 		    match_pattern_list(var_name, denylist, 0) != 1) {
953989dd127SDag-Erling Smørgrav 			debug3("Copy environment: %s=%s", var_name, var_val);
95409958426SBrian Feldman 			child_set_env(env, envsize, var_name, var_val);
9554f52dfbbSDag-Erling Smørgrav 		}
956989dd127SDag-Erling Smørgrav 
957e4a9863fSDag-Erling Smørgrav 		free(var_name);
95809958426SBrian Feldman 	}
95909958426SBrian Feldman }
96019261079SEd Maste #endif /* defined(USE_PAM) || defined(HAVE_CYGWIN) */
96109958426SBrian Feldman 
96219261079SEd Maste #ifdef HAVE_CYGWIN
96319261079SEd Maste static void
copy_environment(char ** source,char *** env,u_int * envsize)9644f52dfbbSDag-Erling Smørgrav copy_environment(char **source, char ***env, u_int *envsize)
965a04a10f8SKris Kennaway {
96619261079SEd Maste 	copy_environment_denylist(source, env, envsize, NULL);
9674f52dfbbSDag-Erling Smørgrav }
96819261079SEd Maste #endif
9694f52dfbbSDag-Erling Smørgrav 
9704f52dfbbSDag-Erling Smørgrav static char **
do_setup_env(struct ssh * ssh,Session * s,const char * shell)9714f52dfbbSDag-Erling Smørgrav do_setup_env(struct ssh *ssh, Session *s, const char *shell)
9724f52dfbbSDag-Erling Smørgrav {
973a04a10f8SKris Kennaway 	char buf[256];
97447dd1d1bSDag-Erling Smørgrav 	size_t n;
975af12a3e7SDag-Erling Smørgrav 	u_int i, envsize;
976190cef3dSDag-Erling Smørgrav 	char *ocp, *cp, *value, **env, *laddr;
977333ee039SDag-Erling Smørgrav 	struct passwd *pw = s->pw;
9787aee6ffeSDag-Erling Smørgrav #if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN)
979333ee039SDag-Erling Smørgrav 	char *path = NULL;
980333ee039SDag-Erling Smørgrav #else
981c62005fcSDag-Erling Smørgrav 	extern char **environ;
982ca86bcf2SDag-Erling Smørgrav 	char **senv, **var, *val;
983c62005fcSDag-Erling Smørgrav #endif
984a04a10f8SKris Kennaway 
985a04a10f8SKris Kennaway 	/* Initialize the environment. */
986a04a10f8SKris Kennaway 	envsize = 100;
987333ee039SDag-Erling Smørgrav 	env = xcalloc(envsize, sizeof(char *));
988a04a10f8SKris Kennaway 	env[0] = NULL;
989989dd127SDag-Erling Smørgrav 
990989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN
991989dd127SDag-Erling Smørgrav 	/*
992989dd127SDag-Erling Smørgrav 	 * The Windows environment contains some setting which are
993989dd127SDag-Erling Smørgrav 	 * important for a running system. They must not be dropped.
994989dd127SDag-Erling Smørgrav 	 */
995aa49c926SDag-Erling Smørgrav 	{
996aa49c926SDag-Erling Smørgrav 		char **p;
997aa49c926SDag-Erling Smørgrav 
998aa49c926SDag-Erling Smørgrav 		p = fetch_windows_environment();
999aa49c926SDag-Erling Smørgrav 		copy_environment(p, &env, &envsize);
1000aa49c926SDag-Erling Smørgrav 		free_windows_environment(p);
1001aa49c926SDag-Erling Smørgrav 	}
1002989dd127SDag-Erling Smørgrav #endif
1003a04a10f8SKris Kennaway 
1004c62005fcSDag-Erling Smørgrav 	if (getenv("TZ"))
1005c62005fcSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "TZ", getenv("TZ"));
1006cf2b5f3bSDag-Erling Smørgrav 
1007cf2b5f3bSDag-Erling Smørgrav #ifdef GSSAPI
1008cf2b5f3bSDag-Erling Smørgrav 	/* Allow any GSSAPI methods that we've used to alter
100919261079SEd Maste 	 * the child's environment as they see fit
1010cf2b5f3bSDag-Erling Smørgrav 	 */
1011cf2b5f3bSDag-Erling Smørgrav 	ssh_gssapi_do_child(&env, &envsize);
1012cf2b5f3bSDag-Erling Smørgrav #endif
1013cf2b5f3bSDag-Erling Smørgrav 
1014a04a10f8SKris Kennaway 	/* Set basic environment. */
101521e764dfSDag-Erling Smørgrav 	for (i = 0; i < s->num_env; i++)
1016ca86bcf2SDag-Erling Smørgrav 		child_set_env(&env, &envsize, s->env[i].name, s->env[i].val);
101721e764dfSDag-Erling Smørgrav 
1018a04a10f8SKris Kennaway 	child_set_env(&env, &envsize, "USER", pw->pw_name);
1019a04a10f8SKris Kennaway 	child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
1020e73e9afaSDag-Erling Smørgrav #ifdef _AIX
1021e73e9afaSDag-Erling Smørgrav 	child_set_env(&env, &envsize, "LOGIN", pw->pw_name);
1022e73e9afaSDag-Erling Smørgrav #endif
1023a04a10f8SKris Kennaway 	child_set_env(&env, &envsize, "HOME", pw->pw_dir);
1024ca86bcf2SDag-Erling Smørgrav 	snprintf(buf, sizeof buf, "%.200s/%.50s", _PATH_MAILDIR, pw->pw_name);
1025c62005fcSDag-Erling Smørgrav 	child_set_env(&env, &envsize, "MAIL", buf);
1026989dd127SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1027c62005fcSDag-Erling Smørgrav 	child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
1028c62005fcSDag-Erling Smørgrav 	child_set_env(&env, &envsize, "TERM", "su");
1029ca86bcf2SDag-Erling Smørgrav 	/*
1030ca86bcf2SDag-Erling Smørgrav 	 * Temporarily swap out our real environment with an empty one,
1031ca86bcf2SDag-Erling Smørgrav 	 * let setusercontext() apply any environment variables defined
1032ca86bcf2SDag-Erling Smørgrav 	 * for the user's login class, copy those variables to the child,
1033ca86bcf2SDag-Erling Smørgrav 	 * free the temporary environment, and restore the original.
1034ca86bcf2SDag-Erling Smørgrav 	 */
1035c62005fcSDag-Erling Smørgrav 	senv = environ;
1036ca86bcf2SDag-Erling Smørgrav 	environ = xmalloc(sizeof(*environ));
1037c62005fcSDag-Erling Smørgrav 	*environ = NULL;
1038ca86bcf2SDag-Erling Smørgrav 	(void)setusercontext(lc, pw, pw->pw_uid, LOGIN_SETENV|LOGIN_SETPATH);
1039ca86bcf2SDag-Erling Smørgrav 	for (var = environ; *var != NULL; ++var) {
1040ca86bcf2SDag-Erling Smørgrav 		if ((val = strchr(*var, '=')) != NULL) {
1041ca86bcf2SDag-Erling Smørgrav 			*val++ = '\0';
1042ca86bcf2SDag-Erling Smørgrav 			child_set_env(&env, &envsize, *var, val);
1043ca86bcf2SDag-Erling Smørgrav 		}
1044e4a9863fSDag-Erling Smørgrav 		free(*var);
1045ca86bcf2SDag-Erling Smørgrav 	}
1046e4a9863fSDag-Erling Smørgrav 	free(environ);
1047c62005fcSDag-Erling Smørgrav 	environ = senv;
1048989dd127SDag-Erling Smørgrav #else /* HAVE_LOGIN_CAP */
1049989dd127SDag-Erling Smørgrav # ifndef HAVE_CYGWIN
1050989dd127SDag-Erling Smørgrav 	/*
1051989dd127SDag-Erling Smørgrav 	 * There's no standard path on Windows. The path contains
1052989dd127SDag-Erling Smørgrav 	 * important components pointing to the system directories,
1053989dd127SDag-Erling Smørgrav 	 * needed for loading shared libraries. So the path better
1054989dd127SDag-Erling Smørgrav 	 * remains intact here.
1055989dd127SDag-Erling Smørgrav 	 */
1056cf2b5f3bSDag-Erling Smørgrav #  ifdef HAVE_ETC_DEFAULT_LOGIN
1057cf2b5f3bSDag-Erling Smørgrav 	read_etc_default_login(&env, &envsize, pw->pw_uid);
1058cf2b5f3bSDag-Erling Smørgrav 	path = child_get_env(env, "PATH");
1059cf2b5f3bSDag-Erling Smørgrav #  endif /* HAVE_ETC_DEFAULT_LOGIN */
1060cf2b5f3bSDag-Erling Smørgrav 	if (path == NULL || *path == '\0') {
1061989dd127SDag-Erling Smørgrav 		child_set_env(&env, &envsize, "PATH",
1062ca86bcf2SDag-Erling Smørgrav 		    s->pw->pw_uid == 0 ?  SUPERUSER_PATH : _PATH_STDPATH);
1063cf2b5f3bSDag-Erling Smørgrav 	}
1064989dd127SDag-Erling Smørgrav # endif /* HAVE_CYGWIN */
1065989dd127SDag-Erling Smørgrav #endif /* HAVE_LOGIN_CAP */
1066a04a10f8SKris Kennaway 
1067a04a10f8SKris Kennaway 	/* Normal systems set SHELL by default. */
1068a04a10f8SKris Kennaway 	child_set_env(&env, &envsize, "SHELL", shell);
1069ca86bcf2SDag-Erling Smørgrav 
1070ca3176e7SBrian Feldman 	if (s->term)
1071ca3176e7SBrian Feldman 		child_set_env(&env, &envsize, "TERM", s->term);
1072ca3176e7SBrian Feldman 	if (s->display)
1073ca3176e7SBrian Feldman 		child_set_env(&env, &envsize, "DISPLAY", s->display);
1074989dd127SDag-Erling Smørgrav 
1075aa49c926SDag-Erling Smørgrav 	/*
1076aa49c926SDag-Erling Smørgrav 	 * Since we clear KRB5CCNAME at startup, if it's set now then it
1077aa49c926SDag-Erling Smørgrav 	 * must have been set by a native authentication method (eg AIX or
1078aa49c926SDag-Erling Smørgrav 	 * SIA), so copy it to the child.
1079aa49c926SDag-Erling Smørgrav 	 */
1080aa49c926SDag-Erling Smørgrav 	{
1081aa49c926SDag-Erling Smørgrav 		char *cp;
1082aa49c926SDag-Erling Smørgrav 
1083aa49c926SDag-Erling Smørgrav 		if ((cp = getenv("KRB5CCNAME")) != NULL)
1084aa49c926SDag-Erling Smørgrav 			child_set_env(&env, &envsize, "KRB5CCNAME", cp);
1085aa49c926SDag-Erling Smørgrav 	}
1086aa49c926SDag-Erling Smørgrav 
1087989dd127SDag-Erling Smørgrav #ifdef _AIX
1088989dd127SDag-Erling Smørgrav 	{
1089989dd127SDag-Erling Smørgrav 		char *cp;
1090989dd127SDag-Erling Smørgrav 
1091989dd127SDag-Erling Smørgrav 		if ((cp = getenv("AUTHSTATE")) != NULL)
1092989dd127SDag-Erling Smørgrav 			child_set_env(&env, &envsize, "AUTHSTATE", cp);
1093190cef3dSDag-Erling Smørgrav 		read_environment_file(&env, &envsize, "/etc/environment",
109419261079SEd Maste 		    options.permit_user_env_allowlist);
1095989dd127SDag-Erling Smørgrav 	}
1096989dd127SDag-Erling Smørgrav #endif
1097e8aafc91SKris Kennaway #ifdef KRB5
10985962c0e9SDag-Erling Smørgrav 	if (s->authctxt->krb5_ccname)
1099af12a3e7SDag-Erling Smørgrav 		child_set_env(&env, &envsize, "KRB5CCNAME",
11005962c0e9SDag-Erling Smørgrav 		    s->authctxt->krb5_ccname);
1101af12a3e7SDag-Erling Smørgrav #endif
1102190cef3dSDag-Erling Smørgrav 	if (auth_sock_name != NULL)
1103190cef3dSDag-Erling Smørgrav 		child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
1104190cef3dSDag-Erling Smørgrav 		    auth_sock_name);
1105190cef3dSDag-Erling Smørgrav 
1106190cef3dSDag-Erling Smørgrav 
1107190cef3dSDag-Erling Smørgrav 	/* Set custom environment options from pubkey authentication. */
1108190cef3dSDag-Erling Smørgrav 	if (options.permit_user_env) {
1109190cef3dSDag-Erling Smørgrav 		for (n = 0 ; n < auth_opts->nenv; n++) {
1110190cef3dSDag-Erling Smørgrav 			ocp = xstrdup(auth_opts->env[n]);
1111190cef3dSDag-Erling Smørgrav 			cp = strchr(ocp, '=');
111219261079SEd Maste 			if (cp != NULL) {
1113190cef3dSDag-Erling Smørgrav 				*cp = '\0';
111419261079SEd Maste 				/* Apply PermitUserEnvironment allowlist */
111519261079SEd Maste 				if (options.permit_user_env_allowlist == NULL ||
1116190cef3dSDag-Erling Smørgrav 				    match_pattern_list(ocp,
111719261079SEd Maste 				    options.permit_user_env_allowlist, 0) == 1)
1118190cef3dSDag-Erling Smørgrav 					child_set_env(&env, &envsize,
1119190cef3dSDag-Erling Smørgrav 					    ocp, cp + 1);
1120190cef3dSDag-Erling Smørgrav 			}
1121190cef3dSDag-Erling Smørgrav 			free(ocp);
1122190cef3dSDag-Erling Smørgrav 		}
1123190cef3dSDag-Erling Smørgrav 	}
1124190cef3dSDag-Erling Smørgrav 
1125190cef3dSDag-Erling Smørgrav 	/* read $HOME/.ssh/environment. */
1126190cef3dSDag-Erling Smørgrav 	if (options.permit_user_env) {
112719261079SEd Maste 		snprintf(buf, sizeof buf, "%.200s/%s/environment",
112819261079SEd Maste 		    pw->pw_dir, _PATH_SSH_USER_DIR);
1129190cef3dSDag-Erling Smørgrav 		read_environment_file(&env, &envsize, buf,
113019261079SEd Maste 		    options.permit_user_env_allowlist);
1131190cef3dSDag-Erling Smørgrav 	}
1132190cef3dSDag-Erling Smørgrav 
113309958426SBrian Feldman #ifdef USE_PAM
1134f388f5efSDag-Erling Smørgrav 	/*
1135f388f5efSDag-Erling Smørgrav 	 * Pull in any environment variables that may have
1136f388f5efSDag-Erling Smørgrav 	 * been set by PAM.
1137f388f5efSDag-Erling Smørgrav 	 */
1138ca86bcf2SDag-Erling Smørgrav 	if (options.use_pam) {
11391ec0d754SDag-Erling Smørgrav 		char **p;
1140f388f5efSDag-Erling Smørgrav 
11414f52dfbbSDag-Erling Smørgrav 		/*
114219261079SEd Maste 		 * Don't allow PAM-internal env vars to leak
114319261079SEd Maste 		 * back into the session environment.
11444f52dfbbSDag-Erling Smørgrav 		 */
114519261079SEd Maste #define PAM_ENV_DENYLIST  "SSH_AUTH_INFO*,SSH_CONNECTION*"
11461ec0d754SDag-Erling Smørgrav 		p = fetch_pam_child_environment();
114719261079SEd Maste 		copy_environment_denylist(p, &env, &envsize,
114819261079SEd Maste 		    PAM_ENV_DENYLIST);
11491ec0d754SDag-Erling Smørgrav 		free_pam_environment(p);
11501ec0d754SDag-Erling Smørgrav 
11511ec0d754SDag-Erling Smørgrav 		p = fetch_pam_environment();
115219261079SEd Maste 		copy_environment_denylist(p, &env, &envsize,
115319261079SEd Maste 		    PAM_ENV_DENYLIST);
1154f388f5efSDag-Erling Smørgrav 		free_pam_environment(p);
1155f388f5efSDag-Erling Smørgrav 	}
115609958426SBrian Feldman #endif /* USE_PAM */
115709958426SBrian Feldman 
1158190cef3dSDag-Erling Smørgrav 	/* Environment specified by admin */
1159190cef3dSDag-Erling Smørgrav 	for (i = 0; i < options.num_setenv; i++) {
1160190cef3dSDag-Erling Smørgrav 		cp = xstrdup(options.setenv[i]);
1161190cef3dSDag-Erling Smørgrav 		if ((value = strchr(cp, '=')) == NULL) {
1162190cef3dSDag-Erling Smørgrav 			/* shouldn't happen; vars are checked in servconf.c */
1163190cef3dSDag-Erling Smørgrav 			fatal("Invalid config SetEnv: %s", options.setenv[i]);
1164a04a10f8SKris Kennaway 		}
1165190cef3dSDag-Erling Smørgrav 		*value++ = '\0';
1166190cef3dSDag-Erling Smørgrav 		child_set_env(&env, &envsize, cp, value);
11674d3fc8b0SEd Maste 		free(cp);
1168190cef3dSDag-Erling Smørgrav 	}
1169190cef3dSDag-Erling Smørgrav 
1170190cef3dSDag-Erling Smørgrav 	/* SSH_CLIENT deprecated */
1171190cef3dSDag-Erling Smørgrav 	snprintf(buf, sizeof buf, "%.50s %d %d",
1172190cef3dSDag-Erling Smørgrav 	    ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
1173190cef3dSDag-Erling Smørgrav 	    ssh_local_port(ssh));
1174190cef3dSDag-Erling Smørgrav 	child_set_env(&env, &envsize, "SSH_CLIENT", buf);
1175190cef3dSDag-Erling Smørgrav 
117619261079SEd Maste 	laddr = get_local_ipaddr(ssh_packet_get_connection_in(ssh));
1177190cef3dSDag-Erling Smørgrav 	snprintf(buf, sizeof buf, "%.50s %d %.50s %d",
1178190cef3dSDag-Erling Smørgrav 	    ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
1179190cef3dSDag-Erling Smørgrav 	    laddr, ssh_local_port(ssh));
1180190cef3dSDag-Erling Smørgrav 	free(laddr);
1181190cef3dSDag-Erling Smørgrav 	child_set_env(&env, &envsize, "SSH_CONNECTION", buf);
1182190cef3dSDag-Erling Smørgrav 
1183190cef3dSDag-Erling Smørgrav 	if (tun_fwd_ifnames != NULL)
1184190cef3dSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "SSH_TUNNEL", tun_fwd_ifnames);
1185190cef3dSDag-Erling Smørgrav 	if (auth_info_file != NULL)
1186190cef3dSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "SSH_USER_AUTH", auth_info_file);
1187190cef3dSDag-Erling Smørgrav 	if (s->ttyfd != -1)
1188190cef3dSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "SSH_TTY", s->tty);
1189190cef3dSDag-Erling Smørgrav 	if (original_command)
1190190cef3dSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND",
1191190cef3dSDag-Erling Smørgrav 		    original_command);
1192190cef3dSDag-Erling Smørgrav 
1193a04a10f8SKris Kennaway 	if (debug_flag) {
1194a04a10f8SKris Kennaway 		/* dump the environment */
1195a04a10f8SKris Kennaway 		fprintf(stderr, "Environment:\n");
1196a04a10f8SKris Kennaway 		for (i = 0; env[i]; i++)
1197a04a10f8SKris Kennaway 			fprintf(stderr, "  %.200s\n", env[i]);
1198a04a10f8SKris Kennaway 	}
1199af12a3e7SDag-Erling Smørgrav 	return env;
1200e8aafc91SKris Kennaway }
1201ca3176e7SBrian Feldman 
1202ca3176e7SBrian Feldman /*
1203af12a3e7SDag-Erling Smørgrav  * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found
1204af12a3e7SDag-Erling Smørgrav  * first in this order).
1205ca3176e7SBrian Feldman  */
1206af12a3e7SDag-Erling Smørgrav static void
do_rc_files(struct ssh * ssh,Session * s,const char * shell)120747dd1d1bSDag-Erling Smørgrav do_rc_files(struct ssh *ssh, Session *s, const char *shell)
1208af12a3e7SDag-Erling Smørgrav {
1209af12a3e7SDag-Erling Smørgrav 	FILE *f = NULL;
121019261079SEd Maste 	char *cmd = NULL, *user_rc = NULL;
1211af12a3e7SDag-Erling Smørgrav 	int do_xauth;
1212af12a3e7SDag-Erling Smørgrav 	struct stat st;
1213a04a10f8SKris Kennaway 
1214af12a3e7SDag-Erling Smørgrav 	do_xauth =
1215af12a3e7SDag-Erling Smørgrav 	    s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL;
121619261079SEd Maste 	xasprintf(&user_rc, "%s/%s", s->pw->pw_dir, _PATH_SSH_USER_RC);
1217a04a10f8SKris Kennaway 
1218d4af9e69SDag-Erling Smørgrav 	/* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */
1219d4af9e69SDag-Erling Smørgrav 	if (!s->is_subsystem && options.adm_forced_command == NULL &&
122047dd1d1bSDag-Erling Smørgrav 	    auth_opts->permit_user_rc && options.permit_user_rc &&
122119261079SEd Maste 	    stat(user_rc, &st) >= 0) {
122219261079SEd Maste 		if (xasprintf(&cmd, "%s -c '%s %s'", shell, _PATH_BSHELL,
122319261079SEd Maste 		    user_rc) == -1)
122419261079SEd Maste 			fatal_f("xasprintf: %s", strerror(errno));
1225a04a10f8SKris Kennaway 		if (debug_flag)
1226e9fd63dfSBrian Feldman 			fprintf(stderr, "Running %s\n", cmd);
1227e9fd63dfSBrian Feldman 		f = popen(cmd, "w");
1228a04a10f8SKris Kennaway 		if (f) {
1229ca3176e7SBrian Feldman 			if (do_xauth)
1230ca3176e7SBrian Feldman 				fprintf(f, "%s %s\n", s->auth_proto,
1231ca3176e7SBrian Feldman 				    s->auth_data);
1232a04a10f8SKris Kennaway 			pclose(f);
1233a04a10f8SKris Kennaway 		} else
1234ca3176e7SBrian Feldman 			fprintf(stderr, "Could not run %s\n",
123519261079SEd Maste 			    user_rc);
1236ca3176e7SBrian Feldman 	} else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) {
1237a04a10f8SKris Kennaway 		if (debug_flag)
1238ca3176e7SBrian Feldman 			fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,
1239ca3176e7SBrian Feldman 			    _PATH_SSH_SYSTEM_RC);
1240ca3176e7SBrian Feldman 		f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w");
1241a04a10f8SKris Kennaway 		if (f) {
1242ca3176e7SBrian Feldman 			if (do_xauth)
1243ca3176e7SBrian Feldman 				fprintf(f, "%s %s\n", s->auth_proto,
1244ca3176e7SBrian Feldman 				    s->auth_data);
1245a04a10f8SKris Kennaway 			pclose(f);
1246a04a10f8SKris Kennaway 		} else
1247ca3176e7SBrian Feldman 			fprintf(stderr, "Could not run %s\n",
1248ca3176e7SBrian Feldman 			    _PATH_SSH_SYSTEM_RC);
1249ca3176e7SBrian Feldman 	} else if (do_xauth && options.xauth_location != NULL) {
1250a04a10f8SKris Kennaway 		/* Add authority data to .Xauthority if appropriate. */
1251db1cb46cSKris Kennaway 		if (debug_flag) {
1252db1cb46cSKris Kennaway 			fprintf(stderr,
1253e73e9afaSDag-Erling Smørgrav 			    "Running %.500s remove %.100s\n",
1254e73e9afaSDag-Erling Smørgrav 			    options.xauth_location, s->auth_display);
1255e73e9afaSDag-Erling Smørgrav 			fprintf(stderr,
1256e73e9afaSDag-Erling Smørgrav 			    "%.500s add %.100s %.100s %.100s\n",
1257af12a3e7SDag-Erling Smørgrav 			    options.xauth_location, s->auth_display,
1258ca3176e7SBrian Feldman 			    s->auth_proto, s->auth_data);
1259db1cb46cSKris Kennaway 		}
126019261079SEd Maste 		if (xasprintf(&cmd, "%s -q -", options.xauth_location) == -1)
126119261079SEd Maste 			fatal_f("xasprintf: %s", strerror(errno));
1262c2d3a559SKris Kennaway 		f = popen(cmd, "w");
1263a04a10f8SKris Kennaway 		if (f) {
1264e73e9afaSDag-Erling Smørgrav 			fprintf(f, "remove %s\n",
1265e73e9afaSDag-Erling Smørgrav 			    s->auth_display);
1266af12a3e7SDag-Erling Smørgrav 			fprintf(f, "add %s %s %s\n",
1267af12a3e7SDag-Erling Smørgrav 			    s->auth_display, s->auth_proto,
1268ca3176e7SBrian Feldman 			    s->auth_data);
1269a04a10f8SKris Kennaway 			pclose(f);
1270c2d3a559SKris Kennaway 		} else {
1271c2d3a559SKris Kennaway 			fprintf(stderr, "Could not run %s\n",
1272c2d3a559SKris Kennaway 			    cmd);
1273a04a10f8SKris Kennaway 		}
1274a04a10f8SKris Kennaway 	}
127519261079SEd Maste 	free(cmd);
127619261079SEd Maste 	free(user_rc);
1277a04a10f8SKris Kennaway }
1278ca3176e7SBrian Feldman 
1279af12a3e7SDag-Erling Smørgrav static void
do_nologin(struct passwd * pw)1280af12a3e7SDag-Erling Smørgrav do_nologin(struct passwd *pw)
1281af12a3e7SDag-Erling Smørgrav {
1282af12a3e7SDag-Erling Smørgrav 	FILE *f = NULL;
1283d93a896eSDag-Erling Smørgrav 	const char *nl;
1284d93a896eSDag-Erling Smørgrav 	char buf[1024], *def_nl = _PATH_NOLOGIN;
1285b15c8340SDag-Erling Smørgrav 	struct stat sb;
1286af12a3e7SDag-Erling Smørgrav 
1287af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1288462c32cbSDag-Erling Smørgrav 	if (login_getcapbool(lc, "ignorenologin", 0) || pw->pw_uid == 0)
1289b15c8340SDag-Erling Smørgrav 		return;
1290b15c8340SDag-Erling Smørgrav 	nl = login_getcapstr(lc, "nologin", def_nl, def_nl);
1291af12a3e7SDag-Erling Smørgrav #else
1292b15c8340SDag-Erling Smørgrav 	if (pw->pw_uid == 0)
1293b15c8340SDag-Erling Smørgrav 		return;
1294b15c8340SDag-Erling Smørgrav 	nl = def_nl;
1295af12a3e7SDag-Erling Smørgrav #endif
1296d93a896eSDag-Erling Smørgrav 	if (stat(nl, &sb) == -1)
1297b15c8340SDag-Erling Smørgrav 		return;
1298b15c8340SDag-Erling Smørgrav 
1299b15c8340SDag-Erling Smørgrav 	/* /etc/nologin exists.  Print its contents if we can and exit. */
1300b15c8340SDag-Erling Smørgrav 	logit("User %.100s not allowed because %s exists", pw->pw_name, nl);
1301b15c8340SDag-Erling Smørgrav 	if ((f = fopen(nl, "r")) != NULL) {
1302af12a3e7SDag-Erling Smørgrav 		while (fgets(buf, sizeof(buf), f))
1303af12a3e7SDag-Erling Smørgrav 			fputs(buf, stderr);
1304af12a3e7SDag-Erling Smørgrav 		fclose(f);
1305af12a3e7SDag-Erling Smørgrav 	}
1306b15c8340SDag-Erling Smørgrav 	exit(254);
1307af12a3e7SDag-Erling Smørgrav }
1308af12a3e7SDag-Erling Smørgrav 
1309d4af9e69SDag-Erling Smørgrav /*
1310d4af9e69SDag-Erling Smørgrav  * Chroot into a directory after checking it for safety: all path components
1311d4af9e69SDag-Erling Smørgrav  * must be root-owned directories with strict permissions.
1312d4af9e69SDag-Erling Smørgrav  */
1313d4af9e69SDag-Erling Smørgrav static void
safely_chroot(const char * path,uid_t uid)1314d4af9e69SDag-Erling Smørgrav safely_chroot(const char *path, uid_t uid)
1315d4af9e69SDag-Erling Smørgrav {
1316d4af9e69SDag-Erling Smørgrav 	const char *cp;
1317bc5531deSDag-Erling Smørgrav 	char component[PATH_MAX];
1318d4af9e69SDag-Erling Smørgrav 	struct stat st;
1319d4af9e69SDag-Erling Smørgrav 
132019261079SEd Maste 	if (!path_absolute(path))
1321d4af9e69SDag-Erling Smørgrav 		fatal("chroot path does not begin at root");
1322d4af9e69SDag-Erling Smørgrav 	if (strlen(path) >= sizeof(component))
1323d4af9e69SDag-Erling Smørgrav 		fatal("chroot path too long");
1324d4af9e69SDag-Erling Smørgrav 
1325d4af9e69SDag-Erling Smørgrav 	/*
1326d4af9e69SDag-Erling Smørgrav 	 * Descend the path, checking that each component is a
1327d4af9e69SDag-Erling Smørgrav 	 * root-owned directory with strict permissions.
1328d4af9e69SDag-Erling Smørgrav 	 */
1329d4af9e69SDag-Erling Smørgrav 	for (cp = path; cp != NULL;) {
1330d4af9e69SDag-Erling Smørgrav 		if ((cp = strchr(cp, '/')) == NULL)
1331d4af9e69SDag-Erling Smørgrav 			strlcpy(component, path, sizeof(component));
1332d4af9e69SDag-Erling Smørgrav 		else {
1333d4af9e69SDag-Erling Smørgrav 			cp++;
1334d4af9e69SDag-Erling Smørgrav 			memcpy(component, path, cp - path);
1335d4af9e69SDag-Erling Smørgrav 			component[cp - path] = '\0';
1336d4af9e69SDag-Erling Smørgrav 		}
1337d4af9e69SDag-Erling Smørgrav 
133819261079SEd Maste 		debug3_f("checking '%s'", component);
1339d4af9e69SDag-Erling Smørgrav 
1340d4af9e69SDag-Erling Smørgrav 		if (stat(component, &st) != 0)
134119261079SEd Maste 			fatal_f("stat(\"%s\"): %s",
1342d4af9e69SDag-Erling Smørgrav 			    component, strerror(errno));
1343d4af9e69SDag-Erling Smørgrav 		if (st.st_uid != 0 || (st.st_mode & 022) != 0)
1344d4af9e69SDag-Erling Smørgrav 			fatal("bad ownership or modes for chroot "
1345d4af9e69SDag-Erling Smørgrav 			    "directory %s\"%s\"",
1346d4af9e69SDag-Erling Smørgrav 			    cp == NULL ? "" : "component ", component);
1347d4af9e69SDag-Erling Smørgrav 		if (!S_ISDIR(st.st_mode))
1348d4af9e69SDag-Erling Smørgrav 			fatal("chroot path %s\"%s\" is not a directory",
1349d4af9e69SDag-Erling Smørgrav 			    cp == NULL ? "" : "component ", component);
1350d4af9e69SDag-Erling Smørgrav 
1351d4af9e69SDag-Erling Smørgrav 	}
1352d4af9e69SDag-Erling Smørgrav 
1353d4af9e69SDag-Erling Smørgrav 	if (chdir(path) == -1)
1354d4af9e69SDag-Erling Smørgrav 		fatal("Unable to chdir to chroot path \"%s\": "
1355d4af9e69SDag-Erling Smørgrav 		    "%s", path, strerror(errno));
1356d4af9e69SDag-Erling Smørgrav 	if (chroot(path) == -1)
1357d4af9e69SDag-Erling Smørgrav 		fatal("chroot(\"%s\"): %s", path, strerror(errno));
1358d4af9e69SDag-Erling Smørgrav 	if (chdir("/") == -1)
135919261079SEd Maste 		fatal_f("chdir(/) after chroot: %s", strerror(errno));
1360d4af9e69SDag-Erling Smørgrav 	verbose("Changed root directory to \"%s\"", path);
1361d4af9e69SDag-Erling Smørgrav }
1362d4af9e69SDag-Erling Smørgrav 
1363af12a3e7SDag-Erling Smørgrav /* Set login name, uid, gid, and groups. */
1364989dd127SDag-Erling Smørgrav void
do_setusercontext(struct passwd * pw)136580628bacSDag-Erling Smørgrav do_setusercontext(struct passwd *pw)
1366af12a3e7SDag-Erling Smørgrav {
1367190cef3dSDag-Erling Smørgrav 	char uidstr[32], *chroot_path, *tmp;
1368d4af9e69SDag-Erling Smørgrav 
13694a421b63SDag-Erling Smørgrav 	platform_setusercontext(pw);
1370d4af9e69SDag-Erling Smørgrav 
13714a421b63SDag-Erling Smørgrav 	if (platform_privileged_uidswap()) {
1372989dd127SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1373989dd127SDag-Erling Smørgrav 		if (setusercontext(lc, pw, pw->pw_uid,
1374d4af9e69SDag-Erling Smørgrav 		    (LOGIN_SETALL & ~(LOGIN_SETENV|LOGIN_SETPATH|LOGIN_SETUSER))) < 0) {
1375989dd127SDag-Erling Smørgrav 			perror("unable to set user context");
1376989dd127SDag-Erling Smørgrav 			exit(1);
1377989dd127SDag-Erling Smørgrav 		}
1378989dd127SDag-Erling Smørgrav #else
1379af12a3e7SDag-Erling Smørgrav 		if (setlogin(pw->pw_name) < 0)
1380af12a3e7SDag-Erling Smørgrav 			error("setlogin failed: %s", strerror(errno));
1381af12a3e7SDag-Erling Smørgrav 		if (setgid(pw->pw_gid) < 0) {
1382af12a3e7SDag-Erling Smørgrav 			perror("setgid");
1383af12a3e7SDag-Erling Smørgrav 			exit(1);
1384af12a3e7SDag-Erling Smørgrav 		}
1385af12a3e7SDag-Erling Smørgrav 		/* Initialize the group list. */
1386af12a3e7SDag-Erling Smørgrav 		if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
1387af12a3e7SDag-Erling Smørgrav 			perror("initgroups");
1388af12a3e7SDag-Erling Smørgrav 			exit(1);
1389af12a3e7SDag-Erling Smørgrav 		}
1390af12a3e7SDag-Erling Smørgrav 		endgrent();
1391d4af9e69SDag-Erling Smørgrav #endif
1392b15c8340SDag-Erling Smørgrav 
13934a421b63SDag-Erling Smørgrav 		platform_setusercontext_post_groups(pw);
13948ad9b54aSDag-Erling Smørgrav 
1395acc1a9efSDag-Erling Smørgrav 		if (!in_chroot && options.chroot_directory != NULL &&
1396d4af9e69SDag-Erling Smørgrav 		    strcasecmp(options.chroot_directory, "none") != 0) {
1397d4af9e69SDag-Erling Smørgrav 			tmp = tilde_expand_filename(options.chroot_directory,
1398d4af9e69SDag-Erling Smørgrav 			    pw->pw_uid);
1399190cef3dSDag-Erling Smørgrav 			snprintf(uidstr, sizeof(uidstr), "%llu",
1400190cef3dSDag-Erling Smørgrav 			    (unsigned long long)pw->pw_uid);
1401d4af9e69SDag-Erling Smørgrav 			chroot_path = percent_expand(tmp, "h", pw->pw_dir,
1402190cef3dSDag-Erling Smørgrav 			    "u", pw->pw_name, "U", uidstr, (char *)NULL);
1403d4af9e69SDag-Erling Smørgrav 			safely_chroot(chroot_path, pw->pw_uid);
1404d4af9e69SDag-Erling Smørgrav 			free(tmp);
1405d4af9e69SDag-Erling Smørgrav 			free(chroot_path);
1406e4a9863fSDag-Erling Smørgrav 			/* Make sure we don't attempt to chroot again */
1407e4a9863fSDag-Erling Smørgrav 			free(options.chroot_directory);
1408e4a9863fSDag-Erling Smørgrav 			options.chroot_directory = NULL;
1409acc1a9efSDag-Erling Smørgrav 			in_chroot = 1;
1410d4af9e69SDag-Erling Smørgrav 		}
1411d4af9e69SDag-Erling Smørgrav 
1412d4af9e69SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1413d4af9e69SDag-Erling Smørgrav 		if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUSER) < 0) {
1414d4af9e69SDag-Erling Smørgrav 			perror("unable to set user context (setuser)");
1415d4af9e69SDag-Erling Smørgrav 			exit(1);
1416d4af9e69SDag-Erling Smørgrav 		}
14172ec88e9dSDag-Erling Smørgrav 		/*
14182ec88e9dSDag-Erling Smørgrav 		 * FreeBSD's setusercontext() will not apply the user's
14192ec88e9dSDag-Erling Smørgrav 		 * own umask setting unless running with the user's UID.
14202ec88e9dSDag-Erling Smørgrav 		 */
14216888a9beSDag-Erling Smørgrav 		(void) setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUMASK);
1422d4af9e69SDag-Erling Smørgrav #else
1423f7167e0eSDag-Erling Smørgrav # ifdef USE_LIBIAF
1424acc1a9efSDag-Erling Smørgrav 		/*
1425acc1a9efSDag-Erling Smørgrav 		 * In a chroot environment, the set_id() will always fail;
1426acc1a9efSDag-Erling Smørgrav 		 * typically because of the lack of necessary authentication
1427acc1a9efSDag-Erling Smørgrav 		 * services and runtime such as ./usr/lib/libiaf.so,
1428acc1a9efSDag-Erling Smørgrav 		 * ./usr/lib/libpam.so.1, and ./etc/passwd We skip it in the
1429acc1a9efSDag-Erling Smørgrav 		 * internal sftp chroot case.  We'll lose auditing and ACLs but
1430acc1a9efSDag-Erling Smørgrav 		 * permanently_set_uid will take care of the rest.
1431a0ee8cc6SDag-Erling Smørgrav 		 */
1432acc1a9efSDag-Erling Smørgrav 		if (!in_chroot && set_id(pw->pw_name) != 0)
1433f7167e0eSDag-Erling Smørgrav 			fatal("set_id(%s) Failed", pw->pw_name);
1434f7167e0eSDag-Erling Smørgrav # endif /* USE_LIBIAF */
1435af12a3e7SDag-Erling Smørgrav 		/* Permanently switch to the desired uid. */
1436af12a3e7SDag-Erling Smørgrav 		permanently_set_uid(pw);
1437989dd127SDag-Erling Smørgrav #endif
1438e4a9863fSDag-Erling Smørgrav 	} else if (options.chroot_directory != NULL &&
1439e4a9863fSDag-Erling Smørgrav 	    strcasecmp(options.chroot_directory, "none") != 0) {
1440e4a9863fSDag-Erling Smørgrav 		fatal("server lacks privileges to chroot to ChrootDirectory");
1441af12a3e7SDag-Erling Smørgrav 	}
1442e73e9afaSDag-Erling Smørgrav 
1443af12a3e7SDag-Erling Smørgrav 	if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
1444af12a3e7SDag-Erling Smørgrav 		fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
144580628bacSDag-Erling Smørgrav }
144680628bacSDag-Erling Smørgrav 
144780628bacSDag-Erling Smørgrav static void
do_pwchange(Session * s)14481ec0d754SDag-Erling Smørgrav do_pwchange(Session *s)
14491ec0d754SDag-Erling Smørgrav {
145021e764dfSDag-Erling Smørgrav 	fflush(NULL);
14511ec0d754SDag-Erling Smørgrav 	fprintf(stderr, "WARNING: Your password has expired.\n");
14521ec0d754SDag-Erling Smørgrav 	if (s->ttyfd != -1) {
14531ec0d754SDag-Erling Smørgrav 		fprintf(stderr,
14541ec0d754SDag-Erling Smørgrav 		    "You must change your password now and login again!\n");
1455e146993eSDag-Erling Smørgrav #ifdef WITH_SELINUX
1456e146993eSDag-Erling Smørgrav 		setexeccon(NULL);
1457e146993eSDag-Erling Smørgrav #endif
1458aa49c926SDag-Erling Smørgrav #ifdef PASSWD_NEEDS_USERNAME
1459aa49c926SDag-Erling Smørgrav 		execl(_PATH_PASSWD_PROG, "passwd", s->pw->pw_name,
1460aa49c926SDag-Erling Smørgrav 		    (char *)NULL);
1461aa49c926SDag-Erling Smørgrav #else
14621ec0d754SDag-Erling Smørgrav 		execl(_PATH_PASSWD_PROG, "passwd", (char *)NULL);
1463aa49c926SDag-Erling Smørgrav #endif
14641ec0d754SDag-Erling Smørgrav 		perror("passwd");
14651ec0d754SDag-Erling Smørgrav 	} else {
14661ec0d754SDag-Erling Smørgrav 		fprintf(stderr,
14671ec0d754SDag-Erling Smørgrav 		    "Password change required but no TTY available.\n");
14681ec0d754SDag-Erling Smørgrav 	}
14691ec0d754SDag-Erling Smørgrav 	exit(1);
14701ec0d754SDag-Erling Smørgrav }
14711ec0d754SDag-Erling Smørgrav 
14721ec0d754SDag-Erling Smørgrav static void
child_close_fds(struct ssh * ssh)14734f52dfbbSDag-Erling Smørgrav child_close_fds(struct ssh *ssh)
14741ec0d754SDag-Erling Smørgrav {
1475bc5531deSDag-Erling Smørgrav 	extern int auth_sock;
1476e4a9863fSDag-Erling Smørgrav 
1477bc5531deSDag-Erling Smørgrav 	if (auth_sock != -1) {
1478bc5531deSDag-Erling Smørgrav 		close(auth_sock);
1479bc5531deSDag-Erling Smørgrav 		auth_sock = -1;
1480e4a9863fSDag-Erling Smørgrav 	}
1481e4a9863fSDag-Erling Smørgrav 
148219261079SEd Maste 	if (ssh_packet_get_connection_in(ssh) ==
148319261079SEd Maste 	    ssh_packet_get_connection_out(ssh))
148419261079SEd Maste 		close(ssh_packet_get_connection_in(ssh));
14851ec0d754SDag-Erling Smørgrav 	else {
148619261079SEd Maste 		close(ssh_packet_get_connection_in(ssh));
148719261079SEd Maste 		close(ssh_packet_get_connection_out(ssh));
14881ec0d754SDag-Erling Smørgrav 	}
14891ec0d754SDag-Erling Smørgrav 	/*
14901ec0d754SDag-Erling Smørgrav 	 * Close all descriptors related to channels.  They will still remain
14911ec0d754SDag-Erling Smørgrav 	 * open in the parent.
14921ec0d754SDag-Erling Smørgrav 	 */
14931ec0d754SDag-Erling Smørgrav 	/* XXX better use close-on-exec? -markus */
14944f52dfbbSDag-Erling Smørgrav 	channel_close_all(ssh);
14951ec0d754SDag-Erling Smørgrav 
14961ec0d754SDag-Erling Smørgrav 	/*
14971ec0d754SDag-Erling Smørgrav 	 * Close any extra file descriptors.  Note that there may still be
14981ec0d754SDag-Erling Smørgrav 	 * descriptors left by system functions.  They will be closed later.
14991ec0d754SDag-Erling Smørgrav 	 */
15001ec0d754SDag-Erling Smørgrav 	endpwent();
15011ec0d754SDag-Erling Smørgrav 
150219261079SEd Maste 	/* Stop directing logs to a high-numbered fd before we close it */
150319261079SEd Maste 	log_redirect_stderr_to(NULL);
150419261079SEd Maste 
15051ec0d754SDag-Erling Smørgrav 	/*
1506b74df5b2SDag-Erling Smørgrav 	 * Close any extra open file descriptors so that we don't have them
15071ec0d754SDag-Erling Smørgrav 	 * hanging around in clients.  Note that we want to do this after
15081ec0d754SDag-Erling Smørgrav 	 * initgroups, because at least on Solaris 2.3 it leaves file
15091ec0d754SDag-Erling Smørgrav 	 * descriptors open.
15101ec0d754SDag-Erling Smørgrav 	 */
15114a421b63SDag-Erling Smørgrav 	closefrom(STDERR_FILENO + 1);
15121ec0d754SDag-Erling Smørgrav }
15131ec0d754SDag-Erling Smørgrav 
1514af12a3e7SDag-Erling Smørgrav /*
1515af12a3e7SDag-Erling Smørgrav  * Performs common processing for the child, such as setting up the
1516af12a3e7SDag-Erling Smørgrav  * environment, closing extra file descriptors, setting the user and group
1517af12a3e7SDag-Erling Smørgrav  * ids, and executing the command or shell.
1518af12a3e7SDag-Erling Smørgrav  */
1519d4af9e69SDag-Erling Smørgrav #define ARGV_MAX 10
1520af12a3e7SDag-Erling Smørgrav void
do_child(struct ssh * ssh,Session * s,const char * command)15214f52dfbbSDag-Erling Smørgrav do_child(struct ssh *ssh, Session *s, const char *command)
1522af12a3e7SDag-Erling Smørgrav {
1523af12a3e7SDag-Erling Smørgrav 	extern char **environ;
152419261079SEd Maste 	char **env, *argv[ARGV_MAX], remote_id[512];
1525ca86bcf2SDag-Erling Smørgrav 	const char *shell, *shell0;
1526af12a3e7SDag-Erling Smørgrav 	struct passwd *pw = s->pw;
1527d4af9e69SDag-Erling Smørgrav 	int r = 0;
1528af12a3e7SDag-Erling Smørgrav 
152919261079SEd Maste 	sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id));
153019261079SEd Maste 
1531af12a3e7SDag-Erling Smørgrav 	/* remove hostkey from the child's memory */
1532af12a3e7SDag-Erling Smørgrav 	destroy_sensitive_data();
153319261079SEd Maste 	ssh_packet_clear_keys(ssh);
1534af12a3e7SDag-Erling Smørgrav 
15351ec0d754SDag-Erling Smørgrav 	/* Force a password change */
15361ec0d754SDag-Erling Smørgrav 	if (s->authctxt->force_pwchange) {
15371ec0d754SDag-Erling Smørgrav 		do_setusercontext(pw);
15384f52dfbbSDag-Erling Smørgrav 		child_close_fds(ssh);
15391ec0d754SDag-Erling Smørgrav 		do_pwchange(s);
15401ec0d754SDag-Erling Smørgrav 		exit(1);
15411ec0d754SDag-Erling Smørgrav 	}
15421ec0d754SDag-Erling Smørgrav 
1543af12a3e7SDag-Erling Smørgrav 	/*
1544af12a3e7SDag-Erling Smørgrav 	 * Login(1) does this as well, and it needs uid 0 for the "-h"
1545af12a3e7SDag-Erling Smørgrav 	 * switch, so we let login(1) to this for us.
1546af12a3e7SDag-Erling Smørgrav 	 */
1547989dd127SDag-Erling Smørgrav #ifdef HAVE_OSF_SIA
1548e73e9afaSDag-Erling Smørgrav 	session_setup_sia(pw, s->ttyfd == -1 ? NULL : s->tty);
1549989dd127SDag-Erling Smørgrav 	if (!check_quietlogin(s, command))
1550989dd127SDag-Erling Smørgrav 		do_motd();
1551989dd127SDag-Erling Smørgrav #else /* HAVE_OSF_SIA */
1552b74df5b2SDag-Erling Smørgrav 	/* When PAM is enabled we rely on it to do the nologin check */
1553b74df5b2SDag-Erling Smørgrav 	if (!options.use_pam)
1554af12a3e7SDag-Erling Smørgrav 		do_nologin(pw);
1555989dd127SDag-Erling Smørgrav 	do_setusercontext(pw);
155621e764dfSDag-Erling Smørgrav 	/*
155721e764dfSDag-Erling Smørgrav 	 * PAM session modules in do_setusercontext may have
155821e764dfSDag-Erling Smørgrav 	 * generated messages, so if this in an interactive
155921e764dfSDag-Erling Smørgrav 	 * login then display them too.
156021e764dfSDag-Erling Smørgrav 	 */
1561aa49c926SDag-Erling Smørgrav 	if (!check_quietlogin(s, command))
156221e764dfSDag-Erling Smørgrav 		display_loginmsg();
1563989dd127SDag-Erling Smørgrav #endif /* HAVE_OSF_SIA */
1564af12a3e7SDag-Erling Smørgrav 
1565aa49c926SDag-Erling Smørgrav #ifdef USE_PAM
1566ca86bcf2SDag-Erling Smørgrav 	if (options.use_pam && !is_pam_session_open()) {
1567aa49c926SDag-Erling Smørgrav 		debug3("PAM session not opened, exiting");
1568aa49c926SDag-Erling Smørgrav 		display_loginmsg();
1569aa49c926SDag-Erling Smørgrav 		exit(254);
1570aa49c926SDag-Erling Smørgrav 	}
1571aa49c926SDag-Erling Smørgrav #endif
1572aa49c926SDag-Erling Smørgrav 
1573af12a3e7SDag-Erling Smørgrav 	/*
1574af12a3e7SDag-Erling Smørgrav 	 * Get the shell from the password data.  An empty shell field is
1575af12a3e7SDag-Erling Smørgrav 	 * legal, and means /bin/sh.
1576af12a3e7SDag-Erling Smørgrav 	 */
1577af12a3e7SDag-Erling Smørgrav 	shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
1578e73e9afaSDag-Erling Smørgrav 
1579e73e9afaSDag-Erling Smørgrav 	/*
1580e73e9afaSDag-Erling Smørgrav 	 * Make sure $SHELL points to the shell from the password file,
1581e73e9afaSDag-Erling Smørgrav 	 * even if shell is overridden from login.conf
1582e73e9afaSDag-Erling Smørgrav 	 */
15834f52dfbbSDag-Erling Smørgrav 	env = do_setup_env(ssh, s, shell);
1584e73e9afaSDag-Erling Smørgrav 
1585af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1586af12a3e7SDag-Erling Smørgrav 	shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);
1587af12a3e7SDag-Erling Smørgrav #endif
1588af12a3e7SDag-Erling Smørgrav 
1589af12a3e7SDag-Erling Smørgrav 	/*
1590af12a3e7SDag-Erling Smørgrav 	 * Close the connection descriptors; note that this is the child, and
1591af12a3e7SDag-Erling Smørgrav 	 * the server will still have the socket open, and it is important
1592af12a3e7SDag-Erling Smørgrav 	 * that we do not shutdown it.  Note that the descriptors cannot be
1593af12a3e7SDag-Erling Smørgrav 	 * closed before building the environment, as we call
1594076ad2f8SDag-Erling Smørgrav 	 * ssh_remote_ipaddr there.
1595af12a3e7SDag-Erling Smørgrav 	 */
15964f52dfbbSDag-Erling Smørgrav 	child_close_fds(ssh);
1597af12a3e7SDag-Erling Smørgrav 
1598af12a3e7SDag-Erling Smørgrav 	/*
1599af12a3e7SDag-Erling Smørgrav 	 * Must take new environment into use so that .ssh/rc,
1600af12a3e7SDag-Erling Smørgrav 	 * /etc/ssh/sshrc and xauth are run in the proper environment.
1601af12a3e7SDag-Erling Smørgrav 	 */
1602af12a3e7SDag-Erling Smørgrav 	environ = env;
1603af12a3e7SDag-Erling Smørgrav 
16041ec0d754SDag-Erling Smørgrav #if defined(KRB5) && defined(USE_AFS)
16051ec0d754SDag-Erling Smørgrav 	/*
16061ec0d754SDag-Erling Smørgrav 	 * At this point, we check to see if AFS is active and if we have
16071ec0d754SDag-Erling Smørgrav 	 * a valid Kerberos 5 TGT. If so, it seems like a good idea to see
16081ec0d754SDag-Erling Smørgrav 	 * if we can (and need to) extend the ticket into an AFS token. If
16091ec0d754SDag-Erling Smørgrav 	 * we don't do this, we run into potential problems if the user's
16101ec0d754SDag-Erling Smørgrav 	 * home directory is in AFS and it's not world-readable.
16111ec0d754SDag-Erling Smørgrav 	 */
16121ec0d754SDag-Erling Smørgrav 
16131ec0d754SDag-Erling Smørgrav 	if (options.kerberos_get_afs_token && k_hasafs() &&
16141ec0d754SDag-Erling Smørgrav 	    (s->authctxt->krb5_ctx != NULL)) {
16151ec0d754SDag-Erling Smørgrav 		char cell[64];
16161ec0d754SDag-Erling Smørgrav 
16171ec0d754SDag-Erling Smørgrav 		debug("Getting AFS token");
16181ec0d754SDag-Erling Smørgrav 
16191ec0d754SDag-Erling Smørgrav 		k_setpag();
16201ec0d754SDag-Erling Smørgrav 
16211ec0d754SDag-Erling Smørgrav 		if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
16221ec0d754SDag-Erling Smørgrav 			krb5_afslog(s->authctxt->krb5_ctx,
16231ec0d754SDag-Erling Smørgrav 			    s->authctxt->krb5_fwd_ccache, cell, NULL);
16241ec0d754SDag-Erling Smørgrav 
16251ec0d754SDag-Erling Smørgrav 		krb5_afslog_home(s->authctxt->krb5_ctx,
16261ec0d754SDag-Erling Smørgrav 		    s->authctxt->krb5_fwd_ccache, NULL, NULL, pw->pw_dir);
16271ec0d754SDag-Erling Smørgrav 	}
16281ec0d754SDag-Erling Smørgrav #endif
16291ec0d754SDag-Erling Smørgrav 
1630b74df5b2SDag-Erling Smørgrav 	/* Change current directory to the user's home directory. */
163119261079SEd Maste 	if (chdir(pw->pw_dir) == -1) {
1632d4af9e69SDag-Erling Smørgrav 		/* Suppress missing homedir warning for chroot case */
1633af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1634d4af9e69SDag-Erling Smørgrav 		r = login_getcapbool(lc, "requirehome", 0);
1635af12a3e7SDag-Erling Smørgrav #endif
1636acc1a9efSDag-Erling Smørgrav 		if (r || !in_chroot) {
1637d4af9e69SDag-Erling Smørgrav 			fprintf(stderr, "Could not chdir to home "
1638d4af9e69SDag-Erling Smørgrav 			    "directory %s: %s\n", pw->pw_dir,
1639d4af9e69SDag-Erling Smørgrav 			    strerror(errno));
1640acc1a9efSDag-Erling Smørgrav 		}
1641d4af9e69SDag-Erling Smørgrav 		if (r)
1642d4af9e69SDag-Erling Smørgrav 			exit(1);
1643af12a3e7SDag-Erling Smørgrav 	}
1644af12a3e7SDag-Erling Smørgrav 
1645d4af9e69SDag-Erling Smørgrav 	closefrom(STDERR_FILENO + 1);
1646d4af9e69SDag-Erling Smørgrav 
164747dd1d1bSDag-Erling Smørgrav 	do_rc_files(ssh, s, shell);
1648af12a3e7SDag-Erling Smørgrav 
1649ca3176e7SBrian Feldman 	/* restore SIGPIPE for child */
165019261079SEd Maste 	ssh_signal(SIGPIPE, SIG_DFL);
1651ca3176e7SBrian Feldman 
1652b15c8340SDag-Erling Smørgrav 	if (s->is_subsystem == SUBSYSTEM_INT_SFTP_ERROR) {
165319261079SEd Maste 		error("Connection from %s: refusing non-sftp session",
165419261079SEd Maste 		    remote_id);
1655b15c8340SDag-Erling Smørgrav 		printf("This service allows sftp connections only.\n");
1656b15c8340SDag-Erling Smørgrav 		fflush(NULL);
1657b15c8340SDag-Erling Smørgrav 		exit(1);
1658b15c8340SDag-Erling Smørgrav 	} else if (s->is_subsystem == SUBSYSTEM_INT_SFTP) {
1659d4af9e69SDag-Erling Smørgrav 		extern int optind, optreset;
1660d4af9e69SDag-Erling Smørgrav 		int i;
1661d4af9e69SDag-Erling Smørgrav 		char *p, *args;
1662d4af9e69SDag-Erling Smørgrav 
16637aee6ffeSDag-Erling Smørgrav 		setproctitle("%s@%s", s->pw->pw_name, INTERNAL_SFTP_NAME);
1664cce7d346SDag-Erling Smørgrav 		args = xstrdup(command ? command : "sftp-server");
1665d4af9e69SDag-Erling Smørgrav 		for (i = 0, (p = strtok(args, " ")); p; (p = strtok(NULL, " ")))
1666d4af9e69SDag-Erling Smørgrav 			if (i < ARGV_MAX - 1)
1667d4af9e69SDag-Erling Smørgrav 				argv[i++] = p;
1668d4af9e69SDag-Erling Smørgrav 		argv[i] = NULL;
1669d4af9e69SDag-Erling Smørgrav 		optind = optreset = 1;
1670d4af9e69SDag-Erling Smørgrav 		__progname = argv[0];
1671b15c8340SDag-Erling Smørgrav #ifdef WITH_SELINUX
1672b15c8340SDag-Erling Smørgrav 		ssh_selinux_change_context("sftpd_t");
1673b15c8340SDag-Erling Smørgrav #endif
1674d4af9e69SDag-Erling Smørgrav 		exit(sftp_server_main(i, argv, s->pw));
1675d4af9e69SDag-Erling Smørgrav 	}
1676d4af9e69SDag-Erling Smørgrav 
1677b15c8340SDag-Erling Smørgrav 	fflush(NULL);
1678b15c8340SDag-Erling Smørgrav 
1679af12a3e7SDag-Erling Smørgrav 	/* Get the last component of the shell name. */
1680af12a3e7SDag-Erling Smørgrav 	if ((shell0 = strrchr(shell, '/')) != NULL)
1681af12a3e7SDag-Erling Smørgrav 		shell0++;
1682af12a3e7SDag-Erling Smørgrav 	else
1683af12a3e7SDag-Erling Smørgrav 		shell0 = shell;
1684af12a3e7SDag-Erling Smørgrav 
1685a04a10f8SKris Kennaway 	/*
1686a04a10f8SKris Kennaway 	 * If we have no command, execute the shell.  In this case, the shell
1687a04a10f8SKris Kennaway 	 * name to be passed in argv[0] is preceded by '-' to indicate that
1688a04a10f8SKris Kennaway 	 * this is a login shell.
1689a04a10f8SKris Kennaway 	 */
1690a04a10f8SKris Kennaway 	if (!command) {
1691af12a3e7SDag-Erling Smørgrav 		char argv0[256];
1692a04a10f8SKris Kennaway 
1693a04a10f8SKris Kennaway 		/* Start the shell.  Set initial character to '-'. */
1694af12a3e7SDag-Erling Smørgrav 		argv0[0] = '-';
1695af12a3e7SDag-Erling Smørgrav 
1696af12a3e7SDag-Erling Smørgrav 		if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1)
1697af12a3e7SDag-Erling Smørgrav 		    >= sizeof(argv0) - 1) {
1698af12a3e7SDag-Erling Smørgrav 			errno = EINVAL;
1699af12a3e7SDag-Erling Smørgrav 			perror(shell);
1700af12a3e7SDag-Erling Smørgrav 			exit(1);
1701af12a3e7SDag-Erling Smørgrav 		}
1702a04a10f8SKris Kennaway 
1703a04a10f8SKris Kennaway 		/* Execute the shell. */
1704af12a3e7SDag-Erling Smørgrav 		argv[0] = argv0;
1705a04a10f8SKris Kennaway 		argv[1] = NULL;
1706a04a10f8SKris Kennaway 		execve(shell, argv, env);
1707a04a10f8SKris Kennaway 
1708a04a10f8SKris Kennaway 		/* Executing the shell failed. */
1709a04a10f8SKris Kennaway 		perror(shell);
1710a04a10f8SKris Kennaway 		exit(1);
1711a04a10f8SKris Kennaway 	}
1712a04a10f8SKris Kennaway 	/*
1713a04a10f8SKris Kennaway 	 * Execute the command using the user's shell.  This uses the -c
1714a04a10f8SKris Kennaway 	 * option to execute the command.
1715a04a10f8SKris Kennaway 	 */
1716af12a3e7SDag-Erling Smørgrav 	argv[0] = (char *) shell0;
1717a04a10f8SKris Kennaway 	argv[1] = "-c";
1718a04a10f8SKris Kennaway 	argv[2] = (char *) command;
1719a04a10f8SKris Kennaway 	argv[3] = NULL;
1720a04a10f8SKris Kennaway 	execve(shell, argv, env);
1721a04a10f8SKris Kennaway 	perror(shell);
1722a04a10f8SKris Kennaway 	exit(1);
1723a04a10f8SKris Kennaway }
1724a04a10f8SKris Kennaway 
1725d4af9e69SDag-Erling Smørgrav void
session_unused(int id)1726d4af9e69SDag-Erling Smørgrav session_unused(int id)
1727d4af9e69SDag-Erling Smørgrav {
172819261079SEd Maste 	debug3_f("session id %d unused", id);
1729d4af9e69SDag-Erling Smørgrav 	if (id >= options.max_sessions ||
1730d4af9e69SDag-Erling Smørgrav 	    id >= sessions_nalloc) {
173119261079SEd Maste 		fatal_f("insane session id %d (max %d nalloc %d)",
173219261079SEd Maste 		    id, options.max_sessions, sessions_nalloc);
1733d4af9e69SDag-Erling Smørgrav 	}
1734b83788ffSDag-Erling Smørgrav 	memset(&sessions[id], 0, sizeof(*sessions));
1735d4af9e69SDag-Erling Smørgrav 	sessions[id].self = id;
1736d4af9e69SDag-Erling Smørgrav 	sessions[id].used = 0;
1737d4af9e69SDag-Erling Smørgrav 	sessions[id].chanid = -1;
1738d4af9e69SDag-Erling Smørgrav 	sessions[id].ptyfd = -1;
1739d4af9e69SDag-Erling Smørgrav 	sessions[id].ttyfd = -1;
1740d4af9e69SDag-Erling Smørgrav 	sessions[id].ptymaster = -1;
1741d4af9e69SDag-Erling Smørgrav 	sessions[id].x11_chanids = NULL;
1742d4af9e69SDag-Erling Smørgrav 	sessions[id].next_unused = sessions_first_unused;
1743d4af9e69SDag-Erling Smørgrav 	sessions_first_unused = id;
1744d4af9e69SDag-Erling Smørgrav }
1745d4af9e69SDag-Erling Smørgrav 
1746a04a10f8SKris Kennaway Session *
session_new(void)1747a04a10f8SKris Kennaway session_new(void)
1748a04a10f8SKris Kennaway {
1749d4af9e69SDag-Erling Smørgrav 	Session *s, *tmp;
1750d4af9e69SDag-Erling Smørgrav 
1751d4af9e69SDag-Erling Smørgrav 	if (sessions_first_unused == -1) {
1752d4af9e69SDag-Erling Smørgrav 		if (sessions_nalloc >= options.max_sessions)
1753a04a10f8SKris Kennaway 			return NULL;
175419261079SEd Maste 		debug2_f("allocate (allocated %d max %d)",
175519261079SEd Maste 		    sessions_nalloc, options.max_sessions);
17564f52dfbbSDag-Erling Smørgrav 		tmp = xrecallocarray(sessions, sessions_nalloc,
17574f52dfbbSDag-Erling Smørgrav 		    sessions_nalloc + 1, sizeof(*sessions));
1758d4af9e69SDag-Erling Smørgrav 		if (tmp == NULL) {
175919261079SEd Maste 			error_f("cannot allocate %d sessions",
176019261079SEd Maste 			    sessions_nalloc + 1);
1761d4af9e69SDag-Erling Smørgrav 			return NULL;
1762d4af9e69SDag-Erling Smørgrav 		}
1763d4af9e69SDag-Erling Smørgrav 		sessions = tmp;
1764d4af9e69SDag-Erling Smørgrav 		session_unused(sessions_nalloc++);
1765d4af9e69SDag-Erling Smørgrav 	}
1766d4af9e69SDag-Erling Smørgrav 
1767d4af9e69SDag-Erling Smørgrav 	if (sessions_first_unused >= sessions_nalloc ||
1768d4af9e69SDag-Erling Smørgrav 	    sessions_first_unused < 0) {
176919261079SEd Maste 		fatal_f("insane first_unused %d max %d nalloc %d",
177019261079SEd Maste 		    sessions_first_unused, options.max_sessions,
1771d4af9e69SDag-Erling Smørgrav 		    sessions_nalloc);
1772d4af9e69SDag-Erling Smørgrav 	}
1773d4af9e69SDag-Erling Smørgrav 
1774d4af9e69SDag-Erling Smørgrav 	s = &sessions[sessions_first_unused];
177519261079SEd Maste 	if (s->used)
177619261079SEd Maste 		fatal_f("session %d already used", sessions_first_unused);
1777d4af9e69SDag-Erling Smørgrav 	sessions_first_unused = s->next_unused;
1778d4af9e69SDag-Erling Smørgrav 	s->used = 1;
1779d4af9e69SDag-Erling Smørgrav 	s->next_unused = -1;
1780d4af9e69SDag-Erling Smørgrav 	debug("session_new: session %d", s->self);
1781d4af9e69SDag-Erling Smørgrav 
1782d4af9e69SDag-Erling Smørgrav 	return s;
1783a04a10f8SKris Kennaway }
1784a04a10f8SKris Kennaway 
1785af12a3e7SDag-Erling Smørgrav static void
session_dump(void)1786a04a10f8SKris Kennaway session_dump(void)
1787a04a10f8SKris Kennaway {
1788a04a10f8SKris Kennaway 	int i;
1789d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
1790a04a10f8SKris Kennaway 		Session *s = &sessions[i];
1791d4af9e69SDag-Erling Smørgrav 
179219261079SEd Maste 		debug("dump: used %d next_unused %d session %d "
1793d4af9e69SDag-Erling Smørgrav 		    "channel %d pid %ld",
1794a04a10f8SKris Kennaway 		    s->used,
1795d4af9e69SDag-Erling Smørgrav 		    s->next_unused,
1796a04a10f8SKris Kennaway 		    s->self,
1797a04a10f8SKris Kennaway 		    s->chanid,
179880628bacSDag-Erling Smørgrav 		    (long)s->pid);
1799a04a10f8SKris Kennaway 	}
1800a04a10f8SKris Kennaway }
1801a04a10f8SKris Kennaway 
1802a04a10f8SKris Kennaway int
session_open(Authctxt * authctxt,int chanid)1803af12a3e7SDag-Erling Smørgrav session_open(Authctxt *authctxt, int chanid)
1804a04a10f8SKris Kennaway {
1805a04a10f8SKris Kennaway 	Session *s = session_new();
1806a04a10f8SKris Kennaway 	debug("session_open: channel %d", chanid);
1807a04a10f8SKris Kennaway 	if (s == NULL) {
1808a04a10f8SKris Kennaway 		error("no more sessions");
1809a04a10f8SKris Kennaway 		return 0;
1810a04a10f8SKris Kennaway 	}
1811af12a3e7SDag-Erling Smørgrav 	s->authctxt = authctxt;
1812af12a3e7SDag-Erling Smørgrav 	s->pw = authctxt->pw;
18131ec0d754SDag-Erling Smørgrav 	if (s->pw == NULL || !authctxt->valid)
1814ca3176e7SBrian Feldman 		fatal("no user for session %d", s->self);
1815a04a10f8SKris Kennaway 	debug("session_open: session %d: link with channel %d", s->self, chanid);
1816a04a10f8SKris Kennaway 	s->chanid = chanid;
1817a04a10f8SKris Kennaway 	return 1;
1818a04a10f8SKris Kennaway }
1819a04a10f8SKris Kennaway 
182080628bacSDag-Erling Smørgrav Session *
session_by_tty(char * tty)182180628bacSDag-Erling Smørgrav session_by_tty(char *tty)
182280628bacSDag-Erling Smørgrav {
182380628bacSDag-Erling Smørgrav 	int i;
1824d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
182580628bacSDag-Erling Smørgrav 		Session *s = &sessions[i];
182680628bacSDag-Erling Smørgrav 		if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) {
182780628bacSDag-Erling Smørgrav 			debug("session_by_tty: session %d tty %s", i, tty);
182880628bacSDag-Erling Smørgrav 			return s;
182980628bacSDag-Erling Smørgrav 		}
183080628bacSDag-Erling Smørgrav 	}
183180628bacSDag-Erling Smørgrav 	debug("session_by_tty: unknown tty %.100s", tty);
183280628bacSDag-Erling Smørgrav 	session_dump();
183380628bacSDag-Erling Smørgrav 	return NULL;
183480628bacSDag-Erling Smørgrav }
183580628bacSDag-Erling Smørgrav 
1836af12a3e7SDag-Erling Smørgrav static Session *
session_by_channel(int id)1837a04a10f8SKris Kennaway session_by_channel(int id)
1838a04a10f8SKris Kennaway {
1839a04a10f8SKris Kennaway 	int i;
1840d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
1841a04a10f8SKris Kennaway 		Session *s = &sessions[i];
1842a04a10f8SKris Kennaway 		if (s->used && s->chanid == id) {
1843d4af9e69SDag-Erling Smørgrav 			debug("session_by_channel: session %d channel %d",
1844d4af9e69SDag-Erling Smørgrav 			    i, id);
1845a04a10f8SKris Kennaway 			return s;
1846a04a10f8SKris Kennaway 		}
1847a04a10f8SKris Kennaway 	}
1848a04a10f8SKris Kennaway 	debug("session_by_channel: unknown channel %d", id);
1849a04a10f8SKris Kennaway 	session_dump();
1850a04a10f8SKris Kennaway 	return NULL;
1851a04a10f8SKris Kennaway }
1852a04a10f8SKris Kennaway 
1853af12a3e7SDag-Erling Smørgrav static Session *
session_by_x11_channel(int id)1854d4ecd108SDag-Erling Smørgrav session_by_x11_channel(int id)
1855d4ecd108SDag-Erling Smørgrav {
1856d4ecd108SDag-Erling Smørgrav 	int i, j;
1857d4ecd108SDag-Erling Smørgrav 
1858d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
1859d4ecd108SDag-Erling Smørgrav 		Session *s = &sessions[i];
1860d4ecd108SDag-Erling Smørgrav 
1861d4ecd108SDag-Erling Smørgrav 		if (s->x11_chanids == NULL || !s->used)
1862d4ecd108SDag-Erling Smørgrav 			continue;
1863d4ecd108SDag-Erling Smørgrav 		for (j = 0; s->x11_chanids[j] != -1; j++) {
1864d4ecd108SDag-Erling Smørgrav 			if (s->x11_chanids[j] == id) {
1865d4ecd108SDag-Erling Smørgrav 				debug("session_by_x11_channel: session %d "
1866d4ecd108SDag-Erling Smørgrav 				    "channel %d", s->self, id);
1867d4ecd108SDag-Erling Smørgrav 				return s;
1868d4ecd108SDag-Erling Smørgrav 			}
1869d4ecd108SDag-Erling Smørgrav 		}
1870d4ecd108SDag-Erling Smørgrav 	}
1871d4ecd108SDag-Erling Smørgrav 	debug("session_by_x11_channel: unknown channel %d", id);
1872d4ecd108SDag-Erling Smørgrav 	session_dump();
1873d4ecd108SDag-Erling Smørgrav 	return NULL;
1874d4ecd108SDag-Erling Smørgrav }
1875d4ecd108SDag-Erling Smørgrav 
1876d4ecd108SDag-Erling Smørgrav static Session *
session_by_pid(pid_t pid)1877a04a10f8SKris Kennaway session_by_pid(pid_t pid)
1878a04a10f8SKris Kennaway {
1879a04a10f8SKris Kennaway 	int i;
188080628bacSDag-Erling Smørgrav 	debug("session_by_pid: pid %ld", (long)pid);
1881d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
1882a04a10f8SKris Kennaway 		Session *s = &sessions[i];
1883a04a10f8SKris Kennaway 		if (s->used && s->pid == pid)
1884a04a10f8SKris Kennaway 			return s;
1885a04a10f8SKris Kennaway 	}
188680628bacSDag-Erling Smørgrav 	error("session_by_pid: unknown pid %ld", (long)pid);
1887a04a10f8SKris Kennaway 	session_dump();
1888a04a10f8SKris Kennaway 	return NULL;
1889a04a10f8SKris Kennaway }
1890a04a10f8SKris Kennaway 
1891af12a3e7SDag-Erling Smørgrav static int
session_window_change_req(struct ssh * ssh,Session * s)18924f52dfbbSDag-Erling Smørgrav session_window_change_req(struct ssh *ssh, Session *s)
1893a04a10f8SKris Kennaway {
189419261079SEd Maste 	int r;
189519261079SEd Maste 
189619261079SEd Maste 	if ((r = sshpkt_get_u32(ssh, &s->col)) != 0 ||
189719261079SEd Maste 	    (r = sshpkt_get_u32(ssh, &s->row)) != 0 ||
189819261079SEd Maste 	    (r = sshpkt_get_u32(ssh, &s->xpixel)) != 0 ||
189919261079SEd Maste 	    (r = sshpkt_get_u32(ssh, &s->ypixel)) != 0 ||
190019261079SEd Maste 	    (r = sshpkt_get_end(ssh)) != 0)
190119261079SEd Maste 		sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
1902a04a10f8SKris Kennaway 	pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
1903a04a10f8SKris Kennaway 	return 1;
1904a04a10f8SKris Kennaway }
1905a04a10f8SKris Kennaway 
1906af12a3e7SDag-Erling Smørgrav static int
session_pty_req(struct ssh * ssh,Session * s)19074f52dfbbSDag-Erling Smørgrav session_pty_req(struct ssh *ssh, Session *s)
1908a04a10f8SKris Kennaway {
190919261079SEd Maste 	int r;
1910a04a10f8SKris Kennaway 
191147dd1d1bSDag-Erling Smørgrav 	if (!auth_opts->permit_pty_flag || !options.permit_tty) {
191247dd1d1bSDag-Erling Smørgrav 		debug("Allocating a pty not permitted for this connection.");
1913c2d3a559SKris Kennaway 		return 0;
1914af12a3e7SDag-Erling Smørgrav 	}
1915af12a3e7SDag-Erling Smørgrav 	if (s->ttyfd != -1) {
191619261079SEd Maste 		ssh_packet_disconnect(ssh, "Protocol error: you already have a pty.");
1917a04a10f8SKris Kennaway 		return 0;
1918af12a3e7SDag-Erling Smørgrav 	}
1919af12a3e7SDag-Erling Smørgrav 
192019261079SEd Maste 	if ((r = sshpkt_get_cstring(ssh, &s->term, NULL)) != 0 ||
192119261079SEd Maste 	    (r = sshpkt_get_u32(ssh, &s->col)) != 0 ||
192219261079SEd Maste 	    (r = sshpkt_get_u32(ssh, &s->row)) != 0 ||
192319261079SEd Maste 	    (r = sshpkt_get_u32(ssh, &s->xpixel)) != 0 ||
192419261079SEd Maste 	    (r = sshpkt_get_u32(ssh, &s->ypixel)) != 0)
192519261079SEd Maste 		sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
1926a04a10f8SKris Kennaway 
1927a04a10f8SKris Kennaway 	if (strcmp(s->term, "") == 0) {
1928e4a9863fSDag-Erling Smørgrav 		free(s->term);
1929a04a10f8SKris Kennaway 		s->term = NULL;
1930a04a10f8SKris Kennaway 	}
1931af12a3e7SDag-Erling Smørgrav 
1932a04a10f8SKris Kennaway 	/* Allocate a pty and open it. */
1933af12a3e7SDag-Erling Smørgrav 	debug("Allocating pty.");
19340fdf8faeSEd Maste 	if (!mm_pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) {
1935e4a9863fSDag-Erling Smørgrav 		free(s->term);
1936a04a10f8SKris Kennaway 		s->term = NULL;
1937a04a10f8SKris Kennaway 		s->ptyfd = -1;
1938a04a10f8SKris Kennaway 		s->ttyfd = -1;
1939a04a10f8SKris Kennaway 		error("session_pty_req: session %d alloc failed", s->self);
1940a04a10f8SKris Kennaway 		return 0;
1941a04a10f8SKris Kennaway 	}
1942a04a10f8SKris Kennaway 	debug("session_pty_req: session %d alloc %s", s->self, s->tty);
1943af12a3e7SDag-Erling Smørgrav 
1944190cef3dSDag-Erling Smørgrav 	ssh_tty_parse_modes(ssh, s->ttyfd);
1945af12a3e7SDag-Erling Smørgrav 
194619261079SEd Maste 	if ((r = sshpkt_get_end(ssh)) != 0)
194719261079SEd Maste 		sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
194819261079SEd Maste 
1949af12a3e7SDag-Erling Smørgrav 	/* Set window size from the packet. */
1950a04a10f8SKris Kennaway 	pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
1951a04a10f8SKris Kennaway 
1952a04a10f8SKris Kennaway 	session_proctitle(s);
1953a04a10f8SKris Kennaway 	return 1;
1954a04a10f8SKris Kennaway }
1955a04a10f8SKris Kennaway 
1956af12a3e7SDag-Erling Smørgrav static int
session_subsystem_req(struct ssh * ssh,Session * s)19574f52dfbbSDag-Erling Smørgrav session_subsystem_req(struct ssh *ssh, Session *s)
1958a04a10f8SKris Kennaway {
1959af12a3e7SDag-Erling Smørgrav 	struct stat st;
196019261079SEd Maste 	int r, success = 0;
1961f374ba41SEd Maste 	char *prog, *cmd, *type;
1962d4ecd108SDag-Erling Smørgrav 	u_int i;
1963a04a10f8SKris Kennaway 
196419261079SEd Maste 	if ((r = sshpkt_get_cstring(ssh, &s->subsys, NULL)) != 0 ||
196519261079SEd Maste 	    (r = sshpkt_get_end(ssh)) != 0)
196619261079SEd Maste 		sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
1967f7167e0eSDag-Erling Smørgrav 	debug2("subsystem request for %.100s by user %s", s->subsys,
1968e2f6069cSDag-Erling Smørgrav 	    s->pw->pw_name);
1969a04a10f8SKris Kennaway 
1970c2d3a559SKris Kennaway 	for (i = 0; i < options.num_subsystems; i++) {
1971f7167e0eSDag-Erling Smørgrav 		if (strcmp(s->subsys, options.subsystem_name[i]) == 0) {
1972333ee039SDag-Erling Smørgrav 			prog = options.subsystem_command[i];
1973333ee039SDag-Erling Smørgrav 			cmd = options.subsystem_args[i];
1974b15c8340SDag-Erling Smørgrav 			if (strcmp(INTERNAL_SFTP_NAME, prog) == 0) {
1975d4af9e69SDag-Erling Smørgrav 				s->is_subsystem = SUBSYSTEM_INT_SFTP;
1976b15c8340SDag-Erling Smørgrav 				debug("subsystem: %s", prog);
1977d4af9e69SDag-Erling Smørgrav 			} else {
197819261079SEd Maste 				if (stat(prog, &st) == -1)
1979b15c8340SDag-Erling Smørgrav 					debug("subsystem: cannot stat %s: %s",
1980b15c8340SDag-Erling Smørgrav 					    prog, strerror(errno));
1981d4af9e69SDag-Erling Smørgrav 				s->is_subsystem = SUBSYSTEM_EXT;
1982af12a3e7SDag-Erling Smørgrav 				debug("subsystem: exec() %s", cmd);
1983b15c8340SDag-Erling Smørgrav 			}
1984f374ba41SEd Maste 			xasprintf(&type, "session:subsystem:%s",
1985f374ba41SEd Maste 			    options.subsystem_name[i]);
1986f374ba41SEd Maste 			channel_set_xtype(ssh, s->chanid, type);
1987f374ba41SEd Maste 			free(type);
19884f52dfbbSDag-Erling Smørgrav 			success = do_exec(ssh, s, cmd) == 0;
1989af12a3e7SDag-Erling Smørgrav 			break;
1990c2d3a559SKris Kennaway 		}
1991c2d3a559SKris Kennaway 	}
1992c2d3a559SKris Kennaway 
1993c2d3a559SKris Kennaway 	if (!success)
1994f7167e0eSDag-Erling Smørgrav 		logit("subsystem request for %.100s by user %s failed, "
1995f7167e0eSDag-Erling Smørgrav 		    "subsystem not found", s->subsys, s->pw->pw_name);
1996c2d3a559SKris Kennaway 
1997a04a10f8SKris Kennaway 	return success;
1998a04a10f8SKris Kennaway }
1999a04a10f8SKris Kennaway 
2000af12a3e7SDag-Erling Smørgrav static int
session_x11_req(struct ssh * ssh,Session * s)20014f52dfbbSDag-Erling Smørgrav session_x11_req(struct ssh *ssh, Session *s)
2002a04a10f8SKris Kennaway {
200319261079SEd Maste 	int r, success;
200419261079SEd Maste 	u_char single_connection = 0;
2005a04a10f8SKris Kennaway 
2006d4ecd108SDag-Erling Smørgrav 	if (s->auth_proto != NULL || s->auth_data != NULL) {
2007d4ecd108SDag-Erling Smørgrav 		error("session_x11_req: session %d: "
2008b74df5b2SDag-Erling Smørgrav 		    "x11 forwarding already active", s->self);
2009d4ecd108SDag-Erling Smørgrav 		return 0;
2010d4ecd108SDag-Erling Smørgrav 	}
201119261079SEd Maste 	if ((r = sshpkt_get_u8(ssh, &single_connection)) != 0 ||
201219261079SEd Maste 	    (r = sshpkt_get_cstring(ssh, &s->auth_proto, NULL)) != 0 ||
201319261079SEd Maste 	    (r = sshpkt_get_cstring(ssh, &s->auth_data, NULL)) != 0 ||
201419261079SEd Maste 	    (r = sshpkt_get_u32(ssh, &s->screen)) != 0 ||
201519261079SEd Maste 	    (r = sshpkt_get_end(ssh)) != 0)
201619261079SEd Maste 		sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
201719261079SEd Maste 
201819261079SEd Maste 	s->single_connection = single_connection;
2019a04a10f8SKris Kennaway 
2020acc1a9efSDag-Erling Smørgrav 	if (xauth_valid_string(s->auth_proto) &&
2021acc1a9efSDag-Erling Smørgrav 	    xauth_valid_string(s->auth_data))
20224f52dfbbSDag-Erling Smørgrav 		success = session_setup_x11fwd(ssh, s);
2023acc1a9efSDag-Erling Smørgrav 	else {
2024acc1a9efSDag-Erling Smørgrav 		success = 0;
2025acc1a9efSDag-Erling Smørgrav 		error("Invalid X11 forwarding data");
2026acc1a9efSDag-Erling Smørgrav 	}
2027af12a3e7SDag-Erling Smørgrav 	if (!success) {
2028e4a9863fSDag-Erling Smørgrav 		free(s->auth_proto);
2029e4a9863fSDag-Erling Smørgrav 		free(s->auth_data);
2030af12a3e7SDag-Erling Smørgrav 		s->auth_proto = NULL;
2031af12a3e7SDag-Erling Smørgrav 		s->auth_data = NULL;
2032a04a10f8SKris Kennaway 	}
2033af12a3e7SDag-Erling Smørgrav 	return success;
2034a04a10f8SKris Kennaway }
2035a04a10f8SKris Kennaway 
2036af12a3e7SDag-Erling Smørgrav static int
session_shell_req(struct ssh * ssh,Session * s)20374f52dfbbSDag-Erling Smørgrav session_shell_req(struct ssh *ssh, Session *s)
2038c2d3a559SKris Kennaway {
203919261079SEd Maste 	int r;
204019261079SEd Maste 
204119261079SEd Maste 	if ((r = sshpkt_get_end(ssh)) != 0)
204219261079SEd Maste 		sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
2043f374ba41SEd Maste 
2044f374ba41SEd Maste 	channel_set_xtype(ssh, s->chanid, "session:shell");
2045f374ba41SEd Maste 
20464f52dfbbSDag-Erling Smørgrav 	return do_exec(ssh, s, NULL) == 0;
2047c2d3a559SKris Kennaway }
2048c2d3a559SKris Kennaway 
2049af12a3e7SDag-Erling Smørgrav static int
session_exec_req(struct ssh * ssh,Session * s)20504f52dfbbSDag-Erling Smørgrav session_exec_req(struct ssh *ssh, Session *s)
2051c2d3a559SKris Kennaway {
205219261079SEd Maste 	u_int success;
205319261079SEd Maste 	int r;
205419261079SEd Maste 	char *command = NULL;
2055d4af9e69SDag-Erling Smørgrav 
205619261079SEd Maste 	if ((r = sshpkt_get_cstring(ssh, &command, NULL)) != 0 ||
205719261079SEd Maste 	    (r = sshpkt_get_end(ssh)) != 0)
205819261079SEd Maste 		sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
205919261079SEd Maste 
2060f374ba41SEd Maste 	channel_set_xtype(ssh, s->chanid, "session:command");
2061f374ba41SEd Maste 
20624f52dfbbSDag-Erling Smørgrav 	success = do_exec(ssh, s, command) == 0;
2063e4a9863fSDag-Erling Smørgrav 	free(command);
2064d4af9e69SDag-Erling Smørgrav 	return success;
2065c2d3a559SKris Kennaway }
2066c2d3a559SKris Kennaway 
2067af12a3e7SDag-Erling Smørgrav static int
session_break_req(struct ssh * ssh,Session * s)20684f52dfbbSDag-Erling Smørgrav session_break_req(struct ssh *ssh, Session *s)
2069cf2b5f3bSDag-Erling Smørgrav {
207019261079SEd Maste 	int r;
2071cf2b5f3bSDag-Erling Smørgrav 
207219261079SEd Maste 	if ((r = sshpkt_get_u32(ssh, NULL)) != 0 || /* ignore */
207319261079SEd Maste 	    (r = sshpkt_get_end(ssh)) != 0)
207419261079SEd Maste 		sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
2075cf2b5f3bSDag-Erling Smørgrav 
207619261079SEd Maste 	if (s->ptymaster == -1 || tcsendbreak(s->ptymaster, 0) == -1)
2077cf2b5f3bSDag-Erling Smørgrav 		return 0;
2078cf2b5f3bSDag-Erling Smørgrav 	return 1;
2079cf2b5f3bSDag-Erling Smørgrav }
2080cf2b5f3bSDag-Erling Smørgrav 
2081cf2b5f3bSDag-Erling Smørgrav static int
session_env_req(struct ssh * ssh,Session * s)20824f52dfbbSDag-Erling Smørgrav session_env_req(struct ssh *ssh, Session *s)
208321e764dfSDag-Erling Smørgrav {
208421e764dfSDag-Erling Smørgrav 	char *name, *val;
208519261079SEd Maste 	u_int i;
208619261079SEd Maste 	int r;
208721e764dfSDag-Erling Smørgrav 
208819261079SEd Maste 	if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0 ||
208919261079SEd Maste 	    (r = sshpkt_get_cstring(ssh, &val, NULL)) != 0 ||
209019261079SEd Maste 	    (r = sshpkt_get_end(ssh)) != 0)
209119261079SEd Maste 		sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
209221e764dfSDag-Erling Smørgrav 
209321e764dfSDag-Erling Smørgrav 	/* Don't set too many environment variables */
209421e764dfSDag-Erling Smørgrav 	if (s->num_env > 128) {
209521e764dfSDag-Erling Smørgrav 		debug2("Ignoring env request %s: too many env vars", name);
209621e764dfSDag-Erling Smørgrav 		goto fail;
209721e764dfSDag-Erling Smørgrav 	}
209821e764dfSDag-Erling Smørgrav 
209921e764dfSDag-Erling Smørgrav 	for (i = 0; i < options.num_accept_env; i++) {
210021e764dfSDag-Erling Smørgrav 		if (match_pattern(name, options.accept_env[i])) {
210121e764dfSDag-Erling Smørgrav 			debug2("Setting env %d: %s=%s", s->num_env, name, val);
21024f52dfbbSDag-Erling Smørgrav 			s->env = xrecallocarray(s->env, s->num_env,
21034f52dfbbSDag-Erling Smørgrav 			    s->num_env + 1, sizeof(*s->env));
210421e764dfSDag-Erling Smørgrav 			s->env[s->num_env].name = name;
210521e764dfSDag-Erling Smørgrav 			s->env[s->num_env].val = val;
210621e764dfSDag-Erling Smørgrav 			s->num_env++;
210721e764dfSDag-Erling Smørgrav 			return (1);
210821e764dfSDag-Erling Smørgrav 		}
210921e764dfSDag-Erling Smørgrav 	}
211021e764dfSDag-Erling Smørgrav 	debug2("Ignoring env request %s: disallowed name", name);
211121e764dfSDag-Erling Smørgrav 
211221e764dfSDag-Erling Smørgrav  fail:
2113e4a9863fSDag-Erling Smørgrav 	free(name);
2114e4a9863fSDag-Erling Smørgrav 	free(val);
211521e764dfSDag-Erling Smørgrav 	return (0);
211621e764dfSDag-Erling Smørgrav }
211721e764dfSDag-Erling Smørgrav 
21182f513db7SEd Maste /*
21192f513db7SEd Maste  * Conversion of signals from ssh channel request names.
21202f513db7SEd Maste  * Subset of signals from RFC 4254 section 6.10C, with SIGINFO as
21212f513db7SEd Maste  * local extension.
21222f513db7SEd Maste  */
21232f513db7SEd Maste static int
name2sig(char * name)21242f513db7SEd Maste name2sig(char *name)
21252f513db7SEd Maste {
21262f513db7SEd Maste #define SSH_SIG(x) if (strcmp(name, #x) == 0) return SIG ## x
21272f513db7SEd Maste 	SSH_SIG(HUP);
21282f513db7SEd Maste 	SSH_SIG(INT);
21292f513db7SEd Maste 	SSH_SIG(KILL);
21302f513db7SEd Maste 	SSH_SIG(QUIT);
21312f513db7SEd Maste 	SSH_SIG(TERM);
21322f513db7SEd Maste 	SSH_SIG(USR1);
21332f513db7SEd Maste 	SSH_SIG(USR2);
21342f513db7SEd Maste #undef	SSH_SIG
21352f513db7SEd Maste #ifdef SIGINFO
21362f513db7SEd Maste 	if (strcmp(name, "INFO@openssh.com") == 0)
21372f513db7SEd Maste 		return SIGINFO;
21382f513db7SEd Maste #endif
21392f513db7SEd Maste 	return -1;
21402f513db7SEd Maste }
21412f513db7SEd Maste 
21422f513db7SEd Maste static int
session_signal_req(struct ssh * ssh,Session * s)21432f513db7SEd Maste session_signal_req(struct ssh *ssh, Session *s)
21442f513db7SEd Maste {
21452f513db7SEd Maste 	char *signame = NULL;
21462f513db7SEd Maste 	int r, sig, success = 0;
21472f513db7SEd Maste 
21482f513db7SEd Maste 	if ((r = sshpkt_get_cstring(ssh, &signame, NULL)) != 0 ||
21492f513db7SEd Maste 	    (r = sshpkt_get_end(ssh)) != 0) {
215019261079SEd Maste 		error_fr(r, "parse");
21512f513db7SEd Maste 		goto out;
21522f513db7SEd Maste 	}
21532f513db7SEd Maste 	if ((sig = name2sig(signame)) == -1) {
215419261079SEd Maste 		error_f("unsupported signal \"%s\"", signame);
21552f513db7SEd Maste 		goto out;
21562f513db7SEd Maste 	}
21572f513db7SEd Maste 	if (s->pid <= 0) {
215819261079SEd Maste 		error_f("no pid for session %d", s->self);
21592f513db7SEd Maste 		goto out;
21602f513db7SEd Maste 	}
21612f513db7SEd Maste 	if (s->forced || s->is_subsystem) {
216219261079SEd Maste 		error_f("refusing to send signal %s to %s session",
21632f513db7SEd Maste 		    signame, s->forced ? "forced-command" : "subsystem");
21642f513db7SEd Maste 		goto out;
21652f513db7SEd Maste 	}
21660fdf8faeSEd Maste 	if (mm_is_monitor()) {
216719261079SEd Maste 		error_f("session signalling requires privilege separation");
21682f513db7SEd Maste 		goto out;
21692f513db7SEd Maste 	}
21702f513db7SEd Maste 
217119261079SEd Maste 	debug_f("signal %s, killpg(%ld, %d)", signame, (long)s->pid, sig);
21722f513db7SEd Maste 	temporarily_use_uid(s->pw);
21732f513db7SEd Maste 	r = killpg(s->pid, sig);
21742f513db7SEd Maste 	restore_uid();
21752f513db7SEd Maste 	if (r != 0) {
217619261079SEd Maste 		error_f("killpg(%ld, %d): %s", (long)s->pid,
21772f513db7SEd Maste 		    sig, strerror(errno));
21782f513db7SEd Maste 		goto out;
21792f513db7SEd Maste 	}
21802f513db7SEd Maste 
21812f513db7SEd Maste 	/* success */
21822f513db7SEd Maste 	success = 1;
21832f513db7SEd Maste  out:
21842f513db7SEd Maste 	free(signame);
21852f513db7SEd Maste 	return success;
21862f513db7SEd Maste }
21872f513db7SEd Maste 
218821e764dfSDag-Erling Smørgrav static int
session_auth_agent_req(struct ssh * ssh,Session * s)21894f52dfbbSDag-Erling Smørgrav session_auth_agent_req(struct ssh *ssh, Session *s)
2190ca3176e7SBrian Feldman {
2191ca3176e7SBrian Feldman 	static int called = 0;
219219261079SEd Maste 	int r;
219347dd1d1bSDag-Erling Smørgrav 
219419261079SEd Maste 	if ((r = sshpkt_get_end(ssh)) != 0)
219519261079SEd Maste 		sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
219647dd1d1bSDag-Erling Smørgrav 	if (!auth_opts->permit_agent_forwarding_flag ||
2197*3620d705SEd Maste 	    !options.allow_agent_forwarding ||
2198*3620d705SEd Maste 	    options.disable_forwarding) {
219919261079SEd Maste 		debug_f("agent forwarding disabled");
2200ca3176e7SBrian Feldman 		return 0;
2201ca3176e7SBrian Feldman 	}
2202ca3176e7SBrian Feldman 	if (called) {
2203ca3176e7SBrian Feldman 		return 0;
2204ca3176e7SBrian Feldman 	} else {
2205ca3176e7SBrian Feldman 		called = 1;
22064f52dfbbSDag-Erling Smørgrav 		return auth_input_request_forwarding(ssh, s->pw);
2207ca3176e7SBrian Feldman 	}
2208ca3176e7SBrian Feldman }
2209ca3176e7SBrian Feldman 
2210af12a3e7SDag-Erling Smørgrav int
session_input_channel_req(struct ssh * ssh,Channel * c,const char * rtype)22114f52dfbbSDag-Erling Smørgrav session_input_channel_req(struct ssh *ssh, Channel *c, const char *rtype)
2212a04a10f8SKris Kennaway {
2213a04a10f8SKris Kennaway 	int success = 0;
2214a04a10f8SKris Kennaway 	Session *s;
2215a04a10f8SKris Kennaway 
2216af12a3e7SDag-Erling Smørgrav 	if ((s = session_by_channel(c->self)) == NULL) {
221719261079SEd Maste 		logit_f("no session %d req %.100s", c->self, rtype);
2218af12a3e7SDag-Erling Smørgrav 		return 0;
2219af12a3e7SDag-Erling Smørgrav 	}
222019261079SEd Maste 	debug_f("session %d req %s", s->self, rtype);
2221a04a10f8SKris Kennaway 
2222a04a10f8SKris Kennaway 	/*
2223ca3176e7SBrian Feldman 	 * a session is in LARVAL state until a shell, a command
2224ca3176e7SBrian Feldman 	 * or a subsystem is executed
2225a04a10f8SKris Kennaway 	 */
2226a04a10f8SKris Kennaway 	if (c->type == SSH_CHANNEL_LARVAL) {
2227a04a10f8SKris Kennaway 		if (strcmp(rtype, "shell") == 0) {
22284f52dfbbSDag-Erling Smørgrav 			success = session_shell_req(ssh, s);
2229a04a10f8SKris Kennaway 		} else if (strcmp(rtype, "exec") == 0) {
22304f52dfbbSDag-Erling Smørgrav 			success = session_exec_req(ssh, s);
2231a04a10f8SKris Kennaway 		} else if (strcmp(rtype, "pty-req") == 0) {
22324f52dfbbSDag-Erling Smørgrav 			success = session_pty_req(ssh, s);
2233a04a10f8SKris Kennaway 		} else if (strcmp(rtype, "x11-req") == 0) {
22344f52dfbbSDag-Erling Smørgrav 			success = session_x11_req(ssh, s);
2235ca3176e7SBrian Feldman 		} else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) {
22364f52dfbbSDag-Erling Smørgrav 			success = session_auth_agent_req(ssh, s);
2237a04a10f8SKris Kennaway 		} else if (strcmp(rtype, "subsystem") == 0) {
22384f52dfbbSDag-Erling Smørgrav 			success = session_subsystem_req(ssh, s);
223921e764dfSDag-Erling Smørgrav 		} else if (strcmp(rtype, "env") == 0) {
22404f52dfbbSDag-Erling Smørgrav 			success = session_env_req(ssh, s);
2241a04a10f8SKris Kennaway 		}
2242a04a10f8SKris Kennaway 	}
2243a04a10f8SKris Kennaway 	if (strcmp(rtype, "window-change") == 0) {
22444f52dfbbSDag-Erling Smørgrav 		success = session_window_change_req(ssh, s);
224521e764dfSDag-Erling Smørgrav 	} else if (strcmp(rtype, "break") == 0) {
22464f52dfbbSDag-Erling Smørgrav 		success = session_break_req(ssh, s);
22472f513db7SEd Maste 	} else if (strcmp(rtype, "signal") == 0) {
22482f513db7SEd Maste 		success = session_signal_req(ssh, s);
2249a04a10f8SKris Kennaway 	}
225021e764dfSDag-Erling Smørgrav 
2251af12a3e7SDag-Erling Smørgrav 	return success;
2252a04a10f8SKris Kennaway }
2253a04a10f8SKris Kennaway 
2254a04a10f8SKris Kennaway void
session_set_fds(struct ssh * ssh,Session * s,int fdin,int fdout,int fderr,int ignore_fderr,int is_tty)22554f52dfbbSDag-Erling Smørgrav session_set_fds(struct ssh *ssh, Session *s,
22564f52dfbbSDag-Erling Smørgrav     int fdin, int fdout, int fderr, int ignore_fderr, int is_tty)
2257a04a10f8SKris Kennaway {
2258a04a10f8SKris Kennaway 	/*
2259a04a10f8SKris Kennaway 	 * now that have a child and a pipe to the child,
2260a04a10f8SKris Kennaway 	 * we can activate our channel and register the fd's
2261a04a10f8SKris Kennaway 	 */
2262a04a10f8SKris Kennaway 	if (s->chanid == -1)
2263a04a10f8SKris Kennaway 		fatal("no channel for session %d", s->self);
22644f52dfbbSDag-Erling Smørgrav 	channel_set_fds(ssh, s->chanid,
226560c59fadSDag-Erling Smørgrav 	    fdout, fdin, fderr,
2266e2f6069cSDag-Erling Smørgrav 	    ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
2267d4af9e69SDag-Erling Smørgrav 	    1, is_tty, CHAN_SES_WINDOW_DEFAULT);
2268a04a10f8SKris Kennaway }
2269a04a10f8SKris Kennaway 
2270af12a3e7SDag-Erling Smørgrav /*
2271af12a3e7SDag-Erling Smørgrav  * Function to perform pty cleanup. Also called if we get aborted abnormally
2272af12a3e7SDag-Erling Smørgrav  * (e.g., due to a dropped connection).
2273af12a3e7SDag-Erling Smørgrav  */
227480628bacSDag-Erling Smørgrav void
session_pty_cleanup2(Session * s)22751ec0d754SDag-Erling Smørgrav session_pty_cleanup2(Session *s)
2276a04a10f8SKris Kennaway {
2277af12a3e7SDag-Erling Smørgrav 	if (s == NULL) {
227819261079SEd Maste 		error_f("no session");
2279af12a3e7SDag-Erling Smørgrav 		return;
2280af12a3e7SDag-Erling Smørgrav 	}
2281af12a3e7SDag-Erling Smørgrav 	if (s->ttyfd == -1)
2282a04a10f8SKris Kennaway 		return;
2283a04a10f8SKris Kennaway 
228419261079SEd Maste 	debug_f("session %d release %s", s->self, s->tty);
2285a04a10f8SKris Kennaway 
2286a04a10f8SKris Kennaway 	/* Record that the user has logged out. */
2287af12a3e7SDag-Erling Smørgrav 	if (s->pid != 0)
2288989dd127SDag-Erling Smørgrav 		record_logout(s->pid, s->tty, s->pw->pw_name);
2289a04a10f8SKris Kennaway 
2290a04a10f8SKris Kennaway 	/* Release the pseudo-tty. */
229180628bacSDag-Erling Smørgrav 	if (getuid() == 0)
2292a04a10f8SKris Kennaway 		pty_release(s->tty);
2293a04a10f8SKris Kennaway 
2294a04a10f8SKris Kennaway 	/*
2295a04a10f8SKris Kennaway 	 * Close the server side of the socket pairs.  We must do this after
2296a04a10f8SKris Kennaway 	 * the pty cleanup, so that another process doesn't get this pty
2297a04a10f8SKris Kennaway 	 * while we're still cleaning up.
2298a04a10f8SKris Kennaway 	 */
229919261079SEd Maste 	if (s->ptymaster != -1 && close(s->ptymaster) == -1)
2300d4af9e69SDag-Erling Smørgrav 		error("close(s->ptymaster/%d): %s",
2301d4af9e69SDag-Erling Smørgrav 		    s->ptymaster, strerror(errno));
2302af12a3e7SDag-Erling Smørgrav 
2303af12a3e7SDag-Erling Smørgrav 	/* unlink pty from session */
2304af12a3e7SDag-Erling Smørgrav 	s->ttyfd = -1;
2305a04a10f8SKris Kennaway }
2306a04a10f8SKris Kennaway 
230780628bacSDag-Erling Smørgrav void
session_pty_cleanup(Session * s)23081ec0d754SDag-Erling Smørgrav session_pty_cleanup(Session *s)
230980628bacSDag-Erling Smørgrav {
23100fdf8faeSEd Maste 	mm_session_pty_cleanup2(s);
231180628bacSDag-Erling Smørgrav }
231280628bacSDag-Erling Smørgrav 
2313f388f5efSDag-Erling Smørgrav static char *
sig2name(int sig)2314f388f5efSDag-Erling Smørgrav sig2name(int sig)
2315f388f5efSDag-Erling Smørgrav {
2316f388f5efSDag-Erling Smørgrav #define SSH_SIG(x) if (sig == SIG ## x) return #x
2317f388f5efSDag-Erling Smørgrav 	SSH_SIG(ABRT);
2318f388f5efSDag-Erling Smørgrav 	SSH_SIG(ALRM);
2319f388f5efSDag-Erling Smørgrav 	SSH_SIG(FPE);
2320f388f5efSDag-Erling Smørgrav 	SSH_SIG(HUP);
2321f388f5efSDag-Erling Smørgrav 	SSH_SIG(ILL);
2322f388f5efSDag-Erling Smørgrav 	SSH_SIG(INT);
2323f388f5efSDag-Erling Smørgrav 	SSH_SIG(KILL);
2324f388f5efSDag-Erling Smørgrav 	SSH_SIG(PIPE);
2325f388f5efSDag-Erling Smørgrav 	SSH_SIG(QUIT);
2326f388f5efSDag-Erling Smørgrav 	SSH_SIG(SEGV);
2327f388f5efSDag-Erling Smørgrav 	SSH_SIG(TERM);
2328f388f5efSDag-Erling Smørgrav 	SSH_SIG(USR1);
2329f388f5efSDag-Erling Smørgrav 	SSH_SIG(USR2);
2330f388f5efSDag-Erling Smørgrav #undef	SSH_SIG
2331f388f5efSDag-Erling Smørgrav 	return "SIG@openssh.com";
2332f388f5efSDag-Erling Smørgrav }
2333f388f5efSDag-Erling Smørgrav 
2334af12a3e7SDag-Erling Smørgrav static void
session_close_x11(struct ssh * ssh,int id)23354f52dfbbSDag-Erling Smørgrav session_close_x11(struct ssh *ssh, int id)
2336d4ecd108SDag-Erling Smørgrav {
2337d4ecd108SDag-Erling Smørgrav 	Channel *c;
2338d4ecd108SDag-Erling Smørgrav 
23394f52dfbbSDag-Erling Smørgrav 	if ((c = channel_by_id(ssh, id)) == NULL) {
234019261079SEd Maste 		debug_f("x11 channel %d missing", id);
2341d4ecd108SDag-Erling Smørgrav 	} else {
2342d4ecd108SDag-Erling Smørgrav 		/* Detach X11 listener */
234319261079SEd Maste 		debug_f("detach x11 channel %d", id);
23444f52dfbbSDag-Erling Smørgrav 		channel_cancel_cleanup(ssh, id);
2345d4ecd108SDag-Erling Smørgrav 		if (c->ostate != CHAN_OUTPUT_CLOSED)
23464f52dfbbSDag-Erling Smørgrav 			chan_mark_dead(ssh, c);
2347d4ecd108SDag-Erling Smørgrav 	}
2348d4ecd108SDag-Erling Smørgrav }
2349d4ecd108SDag-Erling Smørgrav 
2350d4ecd108SDag-Erling Smørgrav static void
session_close_single_x11(struct ssh * ssh,int id,int force,void * arg)2351f374ba41SEd Maste session_close_single_x11(struct ssh *ssh, int id, int force, void *arg)
2352d4ecd108SDag-Erling Smørgrav {
2353d4ecd108SDag-Erling Smørgrav 	Session *s;
2354d4ecd108SDag-Erling Smørgrav 	u_int i;
2355d4ecd108SDag-Erling Smørgrav 
235619261079SEd Maste 	debug3_f("channel %d", id);
23574f52dfbbSDag-Erling Smørgrav 	channel_cancel_cleanup(ssh, id);
2358d4ecd108SDag-Erling Smørgrav 	if ((s = session_by_x11_channel(id)) == NULL)
235919261079SEd Maste 		fatal_f("no x11 channel %d", id);
2360d4ecd108SDag-Erling Smørgrav 	for (i = 0; s->x11_chanids[i] != -1; i++) {
236119261079SEd Maste 		debug_f("session %d: closing channel %d",
236219261079SEd Maste 		    s->self, s->x11_chanids[i]);
2363d4ecd108SDag-Erling Smørgrav 		/*
2364d4ecd108SDag-Erling Smørgrav 		 * The channel "id" is already closing, but make sure we
2365d4ecd108SDag-Erling Smørgrav 		 * close all of its siblings.
2366d4ecd108SDag-Erling Smørgrav 		 */
2367d4ecd108SDag-Erling Smørgrav 		if (s->x11_chanids[i] != id)
23684f52dfbbSDag-Erling Smørgrav 			session_close_x11(ssh, s->x11_chanids[i]);
2369d4ecd108SDag-Erling Smørgrav 	}
2370e4a9863fSDag-Erling Smørgrav 	free(s->x11_chanids);
2371d4ecd108SDag-Erling Smørgrav 	s->x11_chanids = NULL;
2372e4a9863fSDag-Erling Smørgrav 	free(s->display);
2373d4ecd108SDag-Erling Smørgrav 	s->display = NULL;
2374e4a9863fSDag-Erling Smørgrav 	free(s->auth_proto);
2375d4ecd108SDag-Erling Smørgrav 	s->auth_proto = NULL;
2376e4a9863fSDag-Erling Smørgrav 	free(s->auth_data);
2377d4ecd108SDag-Erling Smørgrav 	s->auth_data = NULL;
2378e4a9863fSDag-Erling Smørgrav 	free(s->auth_display);
2379d4ecd108SDag-Erling Smørgrav 	s->auth_display = NULL;
2380d4ecd108SDag-Erling Smørgrav }
2381d4ecd108SDag-Erling Smørgrav 
2382d4ecd108SDag-Erling Smørgrav static void
session_exit_message(struct ssh * ssh,Session * s,int status)23834f52dfbbSDag-Erling Smørgrav session_exit_message(struct ssh *ssh, Session *s, int status)
2384a04a10f8SKris Kennaway {
2385a04a10f8SKris Kennaway 	Channel *c;
238619261079SEd Maste 	int r;
2387edf85781SEd Maste 	char *note = NULL;
2388af12a3e7SDag-Erling Smørgrav 
23894f52dfbbSDag-Erling Smørgrav 	if ((c = channel_lookup(ssh, s->chanid)) == NULL)
239019261079SEd Maste 		fatal_f("session %d: no channel %d", s->self, s->chanid);
2391a04a10f8SKris Kennaway 
2392a04a10f8SKris Kennaway 	if (WIFEXITED(status)) {
23934f52dfbbSDag-Erling Smørgrav 		channel_request_start(ssh, s->chanid, "exit-status", 0);
239419261079SEd Maste 		if ((r = sshpkt_put_u32(ssh, WEXITSTATUS(status))) != 0 ||
239519261079SEd Maste 		    (r = sshpkt_send(ssh)) != 0)
239619261079SEd Maste 			sshpkt_fatal(ssh, r, "%s: exit reply", __func__);
2397edf85781SEd Maste 		xasprintf(&note, "exit %d", WEXITSTATUS(status));
2398a04a10f8SKris Kennaway 	} else if (WIFSIGNALED(status)) {
23994f52dfbbSDag-Erling Smørgrav 		channel_request_start(ssh, s->chanid, "exit-signal", 0);
240019261079SEd Maste #ifndef WCOREDUMP
240119261079SEd Maste # define WCOREDUMP(x) (0)
240219261079SEd Maste #endif
240319261079SEd Maste 		if ((r = sshpkt_put_cstring(ssh, sig2name(WTERMSIG(status)))) != 0 ||
240419261079SEd Maste 		    (r = sshpkt_put_u8(ssh, WCOREDUMP(status)? 1 : 0)) != 0 ||
240519261079SEd Maste 		    (r = sshpkt_put_cstring(ssh, "")) != 0 ||
240619261079SEd Maste 		    (r = sshpkt_put_cstring(ssh, "")) != 0 ||
240719261079SEd Maste 		    (r = sshpkt_send(ssh)) != 0)
240819261079SEd Maste 			sshpkt_fatal(ssh, r, "%s: exit reply", __func__);
2409edf85781SEd Maste 		xasprintf(&note, "signal %d%s", WTERMSIG(status),
2410edf85781SEd Maste 		    WCOREDUMP(status) ? " core dumped" : "");
2411a04a10f8SKris Kennaway 	} else {
2412a04a10f8SKris Kennaway 		/* Some weird exit cause.  Just exit. */
2413edf85781SEd Maste 		ssh_packet_disconnect(ssh, "wait returned status %04x.",
2414edf85781SEd Maste 		    status);
2415a04a10f8SKris Kennaway 	}
2416a04a10f8SKris Kennaway 
2417edf85781SEd Maste 	debug_f("session %d channel %d pid %ld %s", s->self, s->chanid,
2418edf85781SEd Maste 	    (long)s->pid, note == NULL ? "UNKNOWN" : note);
2419edf85781SEd Maste 	free(note);
2420edf85781SEd Maste 
2421a04a10f8SKris Kennaway 	/* disconnect channel */
242219261079SEd Maste 	debug_f("release channel %d", s->chanid);
2423b74df5b2SDag-Erling Smørgrav 
2424b74df5b2SDag-Erling Smørgrav 	/*
2425b74df5b2SDag-Erling Smørgrav 	 * Adjust cleanup callback attachment to send close messages when
2426b74df5b2SDag-Erling Smørgrav 	 * the channel gets EOF. The session will be then be closed
242719261079SEd Maste 	 * by session_close_by_channel when the child sessions close their fds.
2428b74df5b2SDag-Erling Smørgrav 	 */
24294f52dfbbSDag-Erling Smørgrav 	channel_register_cleanup(ssh, c->self, session_close_by_channel, 1);
2430b74df5b2SDag-Erling Smørgrav 
2431a04a10f8SKris Kennaway 	/*
2432a04a10f8SKris Kennaway 	 * emulate a write failure with 'chan_write_failed', nobody will be
2433a04a10f8SKris Kennaway 	 * interested in data we write.
2434a04a10f8SKris Kennaway 	 * Note that we must not call 'chan_read_failed', since there could
2435a04a10f8SKris Kennaway 	 * be some more data waiting in the pipe.
2436a04a10f8SKris Kennaway 	 */
2437a04a10f8SKris Kennaway 	if (c->ostate != CHAN_OUTPUT_CLOSED)
24384f52dfbbSDag-Erling Smørgrav 		chan_write_failed(ssh, c);
2439a04a10f8SKris Kennaway }
2440a04a10f8SKris Kennaway 
244180628bacSDag-Erling Smørgrav void
session_close(struct ssh * ssh,Session * s)24424f52dfbbSDag-Erling Smørgrav session_close(struct ssh *ssh, Session *s)
2443a04a10f8SKris Kennaway {
2444d4ecd108SDag-Erling Smørgrav 	u_int i;
244521e764dfSDag-Erling Smørgrav 
2446acc1a9efSDag-Erling Smørgrav 	verbose("Close session: user %s from %.200s port %d id %d",
2447acc1a9efSDag-Erling Smørgrav 	    s->pw->pw_name,
2448076ad2f8SDag-Erling Smørgrav 	    ssh_remote_ipaddr(ssh),
2449076ad2f8SDag-Erling Smørgrav 	    ssh_remote_port(ssh),
2450acc1a9efSDag-Erling Smørgrav 	    s->self);
2451acc1a9efSDag-Erling Smørgrav 
24521ec0d754SDag-Erling Smørgrav 	if (s->ttyfd != -1)
2453af12a3e7SDag-Erling Smørgrav 		session_pty_cleanup(s);
2454e4a9863fSDag-Erling Smørgrav 	free(s->term);
2455e4a9863fSDag-Erling Smørgrav 	free(s->display);
2456e4a9863fSDag-Erling Smørgrav 	free(s->x11_chanids);
2457e4a9863fSDag-Erling Smørgrav 	free(s->auth_display);
2458e4a9863fSDag-Erling Smørgrav 	free(s->auth_data);
2459e4a9863fSDag-Erling Smørgrav 	free(s->auth_proto);
2460f7167e0eSDag-Erling Smørgrav 	free(s->subsys);
2461333ee039SDag-Erling Smørgrav 	if (s->env != NULL) {
246221e764dfSDag-Erling Smørgrav 		for (i = 0; i < s->num_env; i++) {
2463e4a9863fSDag-Erling Smørgrav 			free(s->env[i].name);
2464e4a9863fSDag-Erling Smørgrav 			free(s->env[i].val);
246521e764dfSDag-Erling Smørgrav 		}
2466e4a9863fSDag-Erling Smørgrav 		free(s->env);
2467333ee039SDag-Erling Smørgrav 	}
2468a04a10f8SKris Kennaway 	session_proctitle(s);
2469d4af9e69SDag-Erling Smørgrav 	session_unused(s->self);
2470a04a10f8SKris Kennaway }
2471a04a10f8SKris Kennaway 
2472a04a10f8SKris Kennaway void
session_close_by_pid(struct ssh * ssh,pid_t pid,int status)24734f52dfbbSDag-Erling Smørgrav session_close_by_pid(struct ssh *ssh, pid_t pid, int status)
2474a04a10f8SKris Kennaway {
2475a04a10f8SKris Kennaway 	Session *s = session_by_pid(pid);
2476a04a10f8SKris Kennaway 	if (s == NULL) {
247719261079SEd Maste 		debug_f("no session for pid %ld", (long)pid);
2478a04a10f8SKris Kennaway 		return;
2479a04a10f8SKris Kennaway 	}
2480a04a10f8SKris Kennaway 	if (s->chanid != -1)
24814f52dfbbSDag-Erling Smørgrav 		session_exit_message(ssh, s, status);
2482b74df5b2SDag-Erling Smørgrav 	if (s->ttyfd != -1)
2483b74df5b2SDag-Erling Smørgrav 		session_pty_cleanup(s);
2484333ee039SDag-Erling Smørgrav 	s->pid = 0;
2485a04a10f8SKris Kennaway }
2486a04a10f8SKris Kennaway 
2487a04a10f8SKris Kennaway /*
2488a04a10f8SKris Kennaway  * this is called when a channel dies before
2489a04a10f8SKris Kennaway  * the session 'child' itself dies
2490a04a10f8SKris Kennaway  */
2491a04a10f8SKris Kennaway void
session_close_by_channel(struct ssh * ssh,int id,int force,void * arg)2492f374ba41SEd Maste session_close_by_channel(struct ssh *ssh, int id, int force, void *arg)
2493a04a10f8SKris Kennaway {
2494a04a10f8SKris Kennaway 	Session *s = session_by_channel(id);
2495b74df5b2SDag-Erling Smørgrav 	u_int i;
2496d4ecd108SDag-Erling Smørgrav 
2497a04a10f8SKris Kennaway 	if (s == NULL) {
249819261079SEd Maste 		debug_f("no session for id %d", id);
2499a04a10f8SKris Kennaway 		return;
2500a04a10f8SKris Kennaway 	}
250119261079SEd Maste 	debug_f("channel %d child %ld", id, (long)s->pid);
2502af12a3e7SDag-Erling Smørgrav 	if (s->pid != 0) {
250319261079SEd Maste 		debug_f("channel %d: has child, ttyfd %d", id, s->ttyfd);
2504af12a3e7SDag-Erling Smørgrav 		/*
2505f374ba41SEd Maste 		 * delay detach of session (unless this is a forced close),
2506f374ba41SEd Maste 		 * but release pty, since the fd's to the child are already
2507f374ba41SEd Maste 		 * closed
2508af12a3e7SDag-Erling Smørgrav 		 */
25091ec0d754SDag-Erling Smørgrav 		if (s->ttyfd != -1)
2510af12a3e7SDag-Erling Smørgrav 			session_pty_cleanup(s);
2511f374ba41SEd Maste 		if (!force)
2512af12a3e7SDag-Erling Smørgrav 			return;
2513af12a3e7SDag-Erling Smørgrav 	}
2514af12a3e7SDag-Erling Smørgrav 	/* detach by removing callback */
25154f52dfbbSDag-Erling Smørgrav 	channel_cancel_cleanup(ssh, s->chanid);
2516b74df5b2SDag-Erling Smørgrav 
2517b74df5b2SDag-Erling Smørgrav 	/* Close any X11 listeners associated with this session */
2518b74df5b2SDag-Erling Smørgrav 	if (s->x11_chanids != NULL) {
2519b74df5b2SDag-Erling Smørgrav 		for (i = 0; s->x11_chanids[i] != -1; i++) {
25204f52dfbbSDag-Erling Smørgrav 			session_close_x11(ssh, s->x11_chanids[i]);
2521b74df5b2SDag-Erling Smørgrav 			s->x11_chanids[i] = -1;
2522b74df5b2SDag-Erling Smørgrav 		}
2523b74df5b2SDag-Erling Smørgrav 	}
2524b74df5b2SDag-Erling Smørgrav 
2525a04a10f8SKris Kennaway 	s->chanid = -1;
25264f52dfbbSDag-Erling Smørgrav 	session_close(ssh, s);
2527af12a3e7SDag-Erling Smørgrav }
2528af12a3e7SDag-Erling Smørgrav 
2529af12a3e7SDag-Erling Smørgrav void
session_destroy_all(struct ssh * ssh,void (* closefunc)(Session *))25304f52dfbbSDag-Erling Smørgrav session_destroy_all(struct ssh *ssh, void (*closefunc)(Session *))
2531af12a3e7SDag-Erling Smørgrav {
2532af12a3e7SDag-Erling Smørgrav 	int i;
2533d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
2534af12a3e7SDag-Erling Smørgrav 		Session *s = &sessions[i];
253580628bacSDag-Erling Smørgrav 		if (s->used) {
253680628bacSDag-Erling Smørgrav 			if (closefunc != NULL)
253780628bacSDag-Erling Smørgrav 				closefunc(s);
253880628bacSDag-Erling Smørgrav 			else
25394f52dfbbSDag-Erling Smørgrav 				session_close(ssh, s);
2540a04a10f8SKris Kennaway 		}
2541a04a10f8SKris Kennaway 	}
254280628bacSDag-Erling Smørgrav }
2543a04a10f8SKris Kennaway 
2544af12a3e7SDag-Erling Smørgrav static char *
session_tty_list(void)2545a04a10f8SKris Kennaway session_tty_list(void)
2546a04a10f8SKris Kennaway {
2547a04a10f8SKris Kennaway 	static char buf[1024];
2548a04a10f8SKris Kennaway 	int i;
2549e73e9afaSDag-Erling Smørgrav 	char *cp;
2550e73e9afaSDag-Erling Smørgrav 
2551a04a10f8SKris Kennaway 	buf[0] = '\0';
2552d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
2553a04a10f8SKris Kennaway 		Session *s = &sessions[i];
2554a04a10f8SKris Kennaway 		if (s->used && s->ttyfd != -1) {
2555e73e9afaSDag-Erling Smørgrav 
2556e73e9afaSDag-Erling Smørgrav 			if (strncmp(s->tty, "/dev/", 5) != 0) {
2557e73e9afaSDag-Erling Smørgrav 				cp = strrchr(s->tty, '/');
2558e73e9afaSDag-Erling Smørgrav 				cp = (cp == NULL) ? s->tty : cp + 1;
2559e73e9afaSDag-Erling Smørgrav 			} else
2560e73e9afaSDag-Erling Smørgrav 				cp = s->tty + 5;
2561e73e9afaSDag-Erling Smørgrav 
2562a04a10f8SKris Kennaway 			if (buf[0] != '\0')
2563a04a10f8SKris Kennaway 				strlcat(buf, ",", sizeof buf);
2564e73e9afaSDag-Erling Smørgrav 			strlcat(buf, cp, sizeof buf);
2565a04a10f8SKris Kennaway 		}
2566a04a10f8SKris Kennaway 	}
2567a04a10f8SKris Kennaway 	if (buf[0] == '\0')
2568a04a10f8SKris Kennaway 		strlcpy(buf, "notty", sizeof buf);
2569a04a10f8SKris Kennaway 	return buf;
2570a04a10f8SKris Kennaway }
2571a04a10f8SKris Kennaway 
2572a04a10f8SKris Kennaway void
session_proctitle(Session * s)2573a04a10f8SKris Kennaway session_proctitle(Session *s)
2574a04a10f8SKris Kennaway {
2575a04a10f8SKris Kennaway 	if (s->pw == NULL)
2576a04a10f8SKris Kennaway 		error("no user for session %d", s->self);
2577a04a10f8SKris Kennaway 	else
2578a04a10f8SKris Kennaway 		setproctitle("%s@%s", s->pw->pw_name, session_tty_list());
2579a04a10f8SKris Kennaway }
2580a04a10f8SKris Kennaway 
2581af12a3e7SDag-Erling Smørgrav int
session_setup_x11fwd(struct ssh * ssh,Session * s)25824f52dfbbSDag-Erling Smørgrav session_setup_x11fwd(struct ssh *ssh, Session *s)
2583af12a3e7SDag-Erling Smørgrav {
2584af12a3e7SDag-Erling Smørgrav 	struct stat st;
2585af12a3e7SDag-Erling Smørgrav 	char display[512], auth_display[512];
2586a0ee8cc6SDag-Erling Smørgrav 	char hostname[NI_MAXHOST];
2587d4ecd108SDag-Erling Smørgrav 	u_int i;
2588af12a3e7SDag-Erling Smørgrav 
258947dd1d1bSDag-Erling Smørgrav 	if (!auth_opts->permit_x11_forwarding_flag) {
259019261079SEd Maste 		ssh_packet_send_debug(ssh, "X11 forwarding disabled by key options.");
2591af12a3e7SDag-Erling Smørgrav 		return 0;
2592af12a3e7SDag-Erling Smørgrav 	}
2593*3620d705SEd Maste 	if (!options.x11_forwarding || options.disable_forwarding) {
2594af12a3e7SDag-Erling Smørgrav 		debug("X11 forwarding disabled in server configuration file.");
2595af12a3e7SDag-Erling Smørgrav 		return 0;
2596af12a3e7SDag-Erling Smørgrav 	}
2597bc5531deSDag-Erling Smørgrav 	if (options.xauth_location == NULL ||
2598af12a3e7SDag-Erling Smørgrav 	    (stat(options.xauth_location, &st) == -1)) {
259919261079SEd Maste 		ssh_packet_send_debug(ssh, "No xauth program; cannot forward X11.");
2600af12a3e7SDag-Erling Smørgrav 		return 0;
2601af12a3e7SDag-Erling Smørgrav 	}
2602af12a3e7SDag-Erling Smørgrav 	if (s->display != NULL) {
2603af12a3e7SDag-Erling Smørgrav 		debug("X11 display already set.");
2604af12a3e7SDag-Erling Smørgrav 		return 0;
2605af12a3e7SDag-Erling Smørgrav 	}
26064f52dfbbSDag-Erling Smørgrav 	if (x11_create_display_inet(ssh, options.x11_display_offset,
2607a82e551fSDag-Erling Smørgrav 	    options.x11_use_localhost, s->single_connection,
2608d4ecd108SDag-Erling Smørgrav 	    &s->display_number, &s->x11_chanids) == -1) {
2609af12a3e7SDag-Erling Smørgrav 		debug("x11_create_display_inet failed.");
2610af12a3e7SDag-Erling Smørgrav 		return 0;
2611af12a3e7SDag-Erling Smørgrav 	}
2612d4ecd108SDag-Erling Smørgrav 	for (i = 0; s->x11_chanids[i] != -1; i++) {
26134f52dfbbSDag-Erling Smørgrav 		channel_register_cleanup(ssh, s->x11_chanids[i],
2614b74df5b2SDag-Erling Smørgrav 		    session_close_single_x11, 0);
2615d4ecd108SDag-Erling Smørgrav 	}
2616af12a3e7SDag-Erling Smørgrav 
2617af12a3e7SDag-Erling Smørgrav 	/* Set up a suitable value for the DISPLAY variable. */
261819261079SEd Maste 	if (gethostname(hostname, sizeof(hostname)) == -1)
2619af12a3e7SDag-Erling Smørgrav 		fatal("gethostname: %.100s", strerror(errno));
2620af12a3e7SDag-Erling Smørgrav 	/*
2621af12a3e7SDag-Erling Smørgrav 	 * auth_display must be used as the displayname when the
2622af12a3e7SDag-Erling Smørgrav 	 * authorization entry is added with xauth(1).  This will be
2623af12a3e7SDag-Erling Smørgrav 	 * different than the DISPLAY string for localhost displays.
2624af12a3e7SDag-Erling Smørgrav 	 */
2625af12a3e7SDag-Erling Smørgrav 	if (options.x11_use_localhost) {
2626a82e551fSDag-Erling Smørgrav 		snprintf(display, sizeof display, "localhost:%u.%u",
2627af12a3e7SDag-Erling Smørgrav 		    s->display_number, s->screen);
2628a82e551fSDag-Erling Smørgrav 		snprintf(auth_display, sizeof auth_display, "unix:%u.%u",
2629af12a3e7SDag-Erling Smørgrav 		    s->display_number, s->screen);
2630af12a3e7SDag-Erling Smørgrav 		s->display = xstrdup(display);
2631af12a3e7SDag-Erling Smørgrav 		s->auth_display = xstrdup(auth_display);
2632af12a3e7SDag-Erling Smørgrav 	} else {
2633989dd127SDag-Erling Smørgrav #ifdef IPADDR_IN_DISPLAY
2634989dd127SDag-Erling Smørgrav 		struct hostent *he;
2635989dd127SDag-Erling Smørgrav 		struct in_addr my_addr;
2636989dd127SDag-Erling Smørgrav 
2637989dd127SDag-Erling Smørgrav 		he = gethostbyname(hostname);
2638989dd127SDag-Erling Smørgrav 		if (he == NULL) {
2639989dd127SDag-Erling Smørgrav 			error("Can't get IP address for X11 DISPLAY.");
264019261079SEd Maste 			ssh_packet_send_debug(ssh, "Can't get IP address for X11 DISPLAY.");
2641989dd127SDag-Erling Smørgrav 			return 0;
2642989dd127SDag-Erling Smørgrav 		}
2643989dd127SDag-Erling Smørgrav 		memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr));
2644a82e551fSDag-Erling Smørgrav 		snprintf(display, sizeof display, "%.50s:%u.%u", inet_ntoa(my_addr),
2645989dd127SDag-Erling Smørgrav 		    s->display_number, s->screen);
2646989dd127SDag-Erling Smørgrav #else
2647a82e551fSDag-Erling Smørgrav 		snprintf(display, sizeof display, "%.400s:%u.%u", hostname,
2648af12a3e7SDag-Erling Smørgrav 		    s->display_number, s->screen);
2649989dd127SDag-Erling Smørgrav #endif
2650af12a3e7SDag-Erling Smørgrav 		s->display = xstrdup(display);
2651af12a3e7SDag-Erling Smørgrav 		s->auth_display = xstrdup(display);
2652af12a3e7SDag-Erling Smørgrav 	}
2653af12a3e7SDag-Erling Smørgrav 
2654af12a3e7SDag-Erling Smørgrav 	return 1;
2655af12a3e7SDag-Erling Smørgrav }
2656af12a3e7SDag-Erling Smørgrav 
2657af12a3e7SDag-Erling Smørgrav static void
do_authenticated2(struct ssh * ssh,Authctxt * authctxt)26584f52dfbbSDag-Erling Smørgrav do_authenticated2(struct ssh *ssh, Authctxt *authctxt)
2659a04a10f8SKris Kennaway {
26604f52dfbbSDag-Erling Smørgrav 	server_loop2(ssh, authctxt);
26611ec0d754SDag-Erling Smørgrav }
26621ec0d754SDag-Erling Smørgrav 
26631ec0d754SDag-Erling Smørgrav void
do_cleanup(struct ssh * ssh,Authctxt * authctxt)26644f52dfbbSDag-Erling Smørgrav do_cleanup(struct ssh *ssh, Authctxt *authctxt)
26651ec0d754SDag-Erling Smørgrav {
26661ec0d754SDag-Erling Smørgrav 	static int called = 0;
26671ec0d754SDag-Erling Smørgrav 
26681ec0d754SDag-Erling Smørgrav 	debug("do_cleanup");
26691ec0d754SDag-Erling Smørgrav 
26701ec0d754SDag-Erling Smørgrav 	/* no cleanup if we're in the child for login shell */
26711ec0d754SDag-Erling Smørgrav 	if (is_child)
26721ec0d754SDag-Erling Smørgrav 		return;
26731ec0d754SDag-Erling Smørgrav 
26741ec0d754SDag-Erling Smørgrav 	/* avoid double cleanup */
26751ec0d754SDag-Erling Smørgrav 	if (called)
26761ec0d754SDag-Erling Smørgrav 		return;
26771ec0d754SDag-Erling Smørgrav 	called = 1;
26781ec0d754SDag-Erling Smørgrav 
2679d4af9e69SDag-Erling Smørgrav 	if (authctxt == NULL)
26801ec0d754SDag-Erling Smørgrav 		return;
2681d4af9e69SDag-Erling Smørgrav 
2682d4af9e69SDag-Erling Smørgrav #ifdef USE_PAM
2683d4af9e69SDag-Erling Smørgrav 	if (options.use_pam) {
2684d4af9e69SDag-Erling Smørgrav 		sshpam_cleanup();
2685d4af9e69SDag-Erling Smørgrav 		sshpam_thread_cleanup();
2686d4af9e69SDag-Erling Smørgrav 	}
2687d4af9e69SDag-Erling Smørgrav #endif
2688d4af9e69SDag-Erling Smørgrav 
2689d4af9e69SDag-Erling Smørgrav 	if (!authctxt->authenticated)
2690d4af9e69SDag-Erling Smørgrav 		return;
2691d4af9e69SDag-Erling Smørgrav 
26921ec0d754SDag-Erling Smørgrav #ifdef KRB5
26931ec0d754SDag-Erling Smørgrav 	if (options.kerberos_ticket_cleanup &&
26941ec0d754SDag-Erling Smørgrav 	    authctxt->krb5_ctx)
26951ec0d754SDag-Erling Smørgrav 		krb5_cleanup_proc(authctxt);
2696cf2b5f3bSDag-Erling Smørgrav #endif
26971ec0d754SDag-Erling Smørgrav 
26981ec0d754SDag-Erling Smørgrav #ifdef GSSAPI
2699ca86bcf2SDag-Erling Smørgrav 	if (options.gss_cleanup_creds)
27001ec0d754SDag-Erling Smørgrav 		ssh_gssapi_cleanup_creds();
27011ec0d754SDag-Erling Smørgrav #endif
27021ec0d754SDag-Erling Smørgrav 
27031ec0d754SDag-Erling Smørgrav 	/* remove agent socket */
27041ec0d754SDag-Erling Smørgrav 	auth_sock_cleanup_proc(authctxt->pw);
27051ec0d754SDag-Erling Smørgrav 
27064f52dfbbSDag-Erling Smørgrav 	/* remove userauth info */
27074f52dfbbSDag-Erling Smørgrav 	if (auth_info_file != NULL) {
27084f52dfbbSDag-Erling Smørgrav 		temporarily_use_uid(authctxt->pw);
27094f52dfbbSDag-Erling Smørgrav 		unlink(auth_info_file);
27104f52dfbbSDag-Erling Smørgrav 		restore_uid();
27114f52dfbbSDag-Erling Smørgrav 		free(auth_info_file);
27124f52dfbbSDag-Erling Smørgrav 		auth_info_file = NULL;
27134f52dfbbSDag-Erling Smørgrav 	}
27144f52dfbbSDag-Erling Smørgrav 
27151ec0d754SDag-Erling Smørgrav 	/*
27161ec0d754SDag-Erling Smørgrav 	 * Cleanup ptys/utmp only if privsep is disabled,
27171ec0d754SDag-Erling Smørgrav 	 * or if running in monitor.
27181ec0d754SDag-Erling Smørgrav 	 */
27190fdf8faeSEd Maste 	if (mm_is_monitor())
27204f52dfbbSDag-Erling Smørgrav 		session_destroy_all(ssh, session_pty_cleanup2);
2721a04a10f8SKris Kennaway }
2722076ad2f8SDag-Erling Smørgrav 
2723076ad2f8SDag-Erling Smørgrav /* Return a name for the remote host that fits inside utmp_size */
2724076ad2f8SDag-Erling Smørgrav 
2725076ad2f8SDag-Erling Smørgrav const char *
session_get_remote_name_or_ip(struct ssh * ssh,u_int utmp_size,int use_dns)2726076ad2f8SDag-Erling Smørgrav session_get_remote_name_or_ip(struct ssh *ssh, u_int utmp_size, int use_dns)
2727076ad2f8SDag-Erling Smørgrav {
2728076ad2f8SDag-Erling Smørgrav 	const char *remote = "";
2729076ad2f8SDag-Erling Smørgrav 
2730076ad2f8SDag-Erling Smørgrav 	if (utmp_size > 0)
2731076ad2f8SDag-Erling Smørgrav 		remote = auth_get_canonical_hostname(ssh, use_dns);
2732076ad2f8SDag-Erling Smørgrav 	if (utmp_size == 0 || strlen(remote) > utmp_size)
2733076ad2f8SDag-Erling Smørgrav 		remote = ssh_remote_ipaddr(ssh);
2734076ad2f8SDag-Erling Smørgrav 	return remote;
2735076ad2f8SDag-Erling Smørgrav }
2736076ad2f8SDag-Erling Smørgrav 
2737