xref: /freebsd/crypto/openssh/session.c (revision 1323ec571215a77ddd21294f0871979d5ad6b992)
1*1323ec57SEd Maste /* $OpenBSD: session.c,v 1.330 2022/02/08 08:59:12 dtucker Exp $ */
2a04a10f8SKris Kennaway /*
3a04a10f8SKris Kennaway  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4a04a10f8SKris Kennaway  *                    All rights reserved
5c2d3a559SKris Kennaway  *
6c2d3a559SKris Kennaway  * As far as I am concerned, the code I have written for this software
7c2d3a559SKris Kennaway  * can be used freely for any purpose.  Any derived versions of this
8c2d3a559SKris Kennaway  * software must be clearly marked as such, and if the derived work is
9c2d3a559SKris Kennaway  * incompatible with the protocol description in the RFC file, it must be
10c2d3a559SKris Kennaway  * called by a name other than "ssh" or "Secure Shell".
11c2d3a559SKris Kennaway  *
12a04a10f8SKris Kennaway  * SSH2 support by Markus Friedl.
13af12a3e7SDag-Erling Smørgrav  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
14e8aafc91SKris Kennaway  *
15c2d3a559SKris Kennaway  * Redistribution and use in source and binary forms, with or without
16c2d3a559SKris Kennaway  * modification, are permitted provided that the following conditions
17c2d3a559SKris Kennaway  * are met:
18c2d3a559SKris Kennaway  * 1. Redistributions of source code must retain the above copyright
19c2d3a559SKris Kennaway  *    notice, this list of conditions and the following disclaimer.
20c2d3a559SKris Kennaway  * 2. Redistributions in binary form must reproduce the above copyright
21c2d3a559SKris Kennaway  *    notice, this list of conditions and the following disclaimer in the
22c2d3a559SKris Kennaway  *    documentation and/or other materials provided with the distribution.
23c2d3a559SKris Kennaway  *
24c2d3a559SKris Kennaway  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25c2d3a559SKris Kennaway  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26c2d3a559SKris Kennaway  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27c2d3a559SKris Kennaway  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28c2d3a559SKris Kennaway  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29c2d3a559SKris Kennaway  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30c2d3a559SKris Kennaway  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31c2d3a559SKris Kennaway  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32c2d3a559SKris Kennaway  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33c2d3a559SKris Kennaway  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34a04a10f8SKris Kennaway  */
35a04a10f8SKris Kennaway 
36a04a10f8SKris Kennaway #include "includes.h"
37333ee039SDag-Erling Smørgrav __RCSID("$FreeBSD$");
38a04a10f8SKris Kennaway 
39333ee039SDag-Erling Smørgrav #include <sys/types.h>
40333ee039SDag-Erling Smørgrav #ifdef HAVE_SYS_STAT_H
41333ee039SDag-Erling Smørgrav # include <sys/stat.h>
42333ee039SDag-Erling Smørgrav #endif
43333ee039SDag-Erling Smørgrav #include <sys/socket.h>
44333ee039SDag-Erling Smørgrav #include <sys/un.h>
45333ee039SDag-Erling Smørgrav #include <sys/wait.h>
46333ee039SDag-Erling Smørgrav 
47333ee039SDag-Erling Smørgrav #include <arpa/inet.h>
48333ee039SDag-Erling Smørgrav 
49acc1a9efSDag-Erling Smørgrav #include <ctype.h>
50333ee039SDag-Erling Smørgrav #include <errno.h>
51e2f6069cSDag-Erling Smørgrav #include <fcntl.h>
52333ee039SDag-Erling Smørgrav #include <grp.h>
53a0ee8cc6SDag-Erling Smørgrav #include <netdb.h>
54333ee039SDag-Erling Smørgrav #ifdef HAVE_PATHS_H
55333ee039SDag-Erling Smørgrav #include <paths.h>
56333ee039SDag-Erling Smørgrav #endif
57333ee039SDag-Erling Smørgrav #include <pwd.h>
58333ee039SDag-Erling Smørgrav #include <signal.h>
59333ee039SDag-Erling Smørgrav #include <stdio.h>
60333ee039SDag-Erling Smørgrav #include <stdlib.h>
61333ee039SDag-Erling Smørgrav #include <string.h>
6219261079SEd Maste #include <stdarg.h>
63333ee039SDag-Erling Smørgrav #include <unistd.h>
64bc5531deSDag-Erling Smørgrav #include <limits.h>
65333ee039SDag-Erling Smørgrav 
66d4af9e69SDag-Erling Smørgrav #include "openbsd-compat/sys-queue.h"
67333ee039SDag-Erling Smørgrav #include "xmalloc.h"
68a04a10f8SKris Kennaway #include "ssh.h"
69ca3176e7SBrian Feldman #include "ssh2.h"
70ca3176e7SBrian Feldman #include "sshpty.h"
71a04a10f8SKris Kennaway #include "packet.h"
72190cef3dSDag-Erling Smørgrav #include "sshbuf.h"
73190cef3dSDag-Erling Smørgrav #include "ssherr.h"
7421e764dfSDag-Erling Smørgrav #include "match.h"
75a04a10f8SKris Kennaway #include "uidswap.h"
76a04a10f8SKris Kennaway #include "compat.h"
77a04a10f8SKris Kennaway #include "channels.h"
78190cef3dSDag-Erling Smørgrav #include "sshkey.h"
79333ee039SDag-Erling Smørgrav #include "cipher.h"
80333ee039SDag-Erling Smørgrav #ifdef GSSAPI
81333ee039SDag-Erling Smørgrav #include "ssh-gss.h"
82333ee039SDag-Erling Smørgrav #endif
83333ee039SDag-Erling Smørgrav #include "hostfile.h"
84a04a10f8SKris Kennaway #include "auth.h"
85c2d3a559SKris Kennaway #include "auth-options.h"
86e4a9863fSDag-Erling Smørgrav #include "authfd.h"
87ca3176e7SBrian Feldman #include "pathnames.h"
88ca3176e7SBrian Feldman #include "log.h"
89a0ee8cc6SDag-Erling Smørgrav #include "misc.h"
90ca3176e7SBrian Feldman #include "servconf.h"
91ca3176e7SBrian Feldman #include "sshlogin.h"
92ca3176e7SBrian Feldman #include "serverloop.h"
93ca3176e7SBrian Feldman #include "canohost.h"
94ca3176e7SBrian Feldman #include "session.h"
95d4ecd108SDag-Erling Smørgrav #include "kex.h"
9680628bacSDag-Erling Smørgrav #include "monitor_wrap.h"
97d4af9e69SDag-Erling Smørgrav #include "sftp.h"
984f52dfbbSDag-Erling Smørgrav #include "atomicio.h"
99a04a10f8SKris Kennaway 
1001ec0d754SDag-Erling Smørgrav #if defined(KRB5) && defined(USE_AFS)
1011ec0d754SDag-Erling Smørgrav #include <kafs.h>
1021ec0d754SDag-Erling Smørgrav #endif
1031ec0d754SDag-Erling Smørgrav 
104e146993eSDag-Erling Smørgrav #ifdef WITH_SELINUX
105e146993eSDag-Erling Smørgrav #include <selinux/selinux.h>
106e146993eSDag-Erling Smørgrav #endif
107e146993eSDag-Erling Smørgrav 
108cce7d346SDag-Erling Smørgrav #define IS_INTERNAL_SFTP(c) \
109cce7d346SDag-Erling Smørgrav 	(!strncmp(c, INTERNAL_SFTP_NAME, sizeof(INTERNAL_SFTP_NAME) - 1) && \
110cce7d346SDag-Erling Smørgrav 	 (c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\0' || \
111cce7d346SDag-Erling Smørgrav 	  c[sizeof(INTERNAL_SFTP_NAME) - 1] == ' ' || \
112cce7d346SDag-Erling Smørgrav 	  c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\t'))
113cce7d346SDag-Erling Smørgrav 
114a04a10f8SKris Kennaway /* func */
115a04a10f8SKris Kennaway 
116a04a10f8SKris Kennaway Session *session_new(void);
1174f52dfbbSDag-Erling Smørgrav void	session_set_fds(struct ssh *, Session *, int, int, int, int, int);
1181ec0d754SDag-Erling Smørgrav void	session_pty_cleanup(Session *);
119af12a3e7SDag-Erling Smørgrav void	session_proctitle(Session *);
1204f52dfbbSDag-Erling Smørgrav int	session_setup_x11fwd(struct ssh *, Session *);
1214f52dfbbSDag-Erling Smørgrav int	do_exec_pty(struct ssh *, Session *, const char *);
1224f52dfbbSDag-Erling Smørgrav int	do_exec_no_pty(struct ssh *, Session *, const char *);
1234f52dfbbSDag-Erling Smørgrav int	do_exec(struct ssh *, Session *, const char *);
1244f52dfbbSDag-Erling Smørgrav void	do_login(struct ssh *, Session *, const char *);
1254f52dfbbSDag-Erling Smørgrav void	do_child(struct ssh *, Session *, const char *);
126ca3176e7SBrian Feldman void	do_motd(void);
127af12a3e7SDag-Erling Smørgrav int	check_quietlogin(Session *, const char *);
128a04a10f8SKris Kennaway 
1294f52dfbbSDag-Erling Smørgrav static void do_authenticated2(struct ssh *, Authctxt *);
130af12a3e7SDag-Erling Smørgrav 
1314f52dfbbSDag-Erling Smørgrav static int session_pty_req(struct ssh *, Session *);
132a04a10f8SKris Kennaway 
133a04a10f8SKris Kennaway /* import */
134a04a10f8SKris Kennaway extern ServerOptions options;
135a04a10f8SKris Kennaway extern char *__progname;
136a04a10f8SKris Kennaway extern int debug_flag;
137ca3176e7SBrian Feldman extern u_int utmp_len;
138c2d3a559SKris Kennaway extern int startup_pipe;
139ca3176e7SBrian Feldman extern void destroy_sensitive_data(void);
140190cef3dSDag-Erling Smørgrav extern struct sshbuf *loginmsg;
14147dd1d1bSDag-Erling Smørgrav extern struct sshauthopt *auth_opts;
1426d0d51a4SKyle Evans extern char *tun_fwd_ifnames; /* serverloop.c */
143a04a10f8SKris Kennaway 
144c2d3a559SKris Kennaway /* original command from peer. */
145af12a3e7SDag-Erling Smørgrav const char *original_command = NULL;
146c2d3a559SKris Kennaway 
147a04a10f8SKris Kennaway /* data */
148d4af9e69SDag-Erling Smørgrav static int sessions_first_unused = -1;
149d4af9e69SDag-Erling Smørgrav static int sessions_nalloc = 0;
150d4af9e69SDag-Erling Smørgrav static Session *sessions = NULL;
151d4af9e69SDag-Erling Smørgrav 
152d4af9e69SDag-Erling Smørgrav #define SUBSYSTEM_NONE			0
153d4af9e69SDag-Erling Smørgrav #define SUBSYSTEM_EXT			1
154d4af9e69SDag-Erling Smørgrav #define SUBSYSTEM_INT_SFTP		2
155b15c8340SDag-Erling Smørgrav #define SUBSYSTEM_INT_SFTP_ERROR	3
156a04a10f8SKris Kennaway 
157c2d3a559SKris Kennaway #ifdef HAVE_LOGIN_CAP
15880628bacSDag-Erling Smørgrav login_cap_t *lc;
159c2d3a559SKris Kennaway #endif
160a04a10f8SKris Kennaway 
1611ec0d754SDag-Erling Smørgrav static int is_child = 0;
162acc1a9efSDag-Erling Smørgrav static int in_chroot = 0;
1631ec0d754SDag-Erling Smørgrav 
1644f52dfbbSDag-Erling Smørgrav /* File containing userauth info, if ExposeAuthInfo set */
1654f52dfbbSDag-Erling Smørgrav static char *auth_info_file = NULL;
1664f52dfbbSDag-Erling Smørgrav 
16780628bacSDag-Erling Smørgrav /* Name and directory of socket for authentication agent forwarding. */
16880628bacSDag-Erling Smørgrav static char *auth_sock_name = NULL;
16980628bacSDag-Erling Smørgrav static char *auth_sock_dir = NULL;
17080628bacSDag-Erling Smørgrav 
17180628bacSDag-Erling Smørgrav /* removes the agent forwarding socket */
17280628bacSDag-Erling Smørgrav 
17380628bacSDag-Erling Smørgrav static void
1741ec0d754SDag-Erling Smørgrav auth_sock_cleanup_proc(struct passwd *pw)
17580628bacSDag-Erling Smørgrav {
17680628bacSDag-Erling Smørgrav 	if (auth_sock_name != NULL) {
17780628bacSDag-Erling Smørgrav 		temporarily_use_uid(pw);
17880628bacSDag-Erling Smørgrav 		unlink(auth_sock_name);
17980628bacSDag-Erling Smørgrav 		rmdir(auth_sock_dir);
18080628bacSDag-Erling Smørgrav 		auth_sock_name = NULL;
18180628bacSDag-Erling Smørgrav 		restore_uid();
18280628bacSDag-Erling Smørgrav 	}
18380628bacSDag-Erling Smørgrav }
18480628bacSDag-Erling Smørgrav 
18580628bacSDag-Erling Smørgrav static int
1864f52dfbbSDag-Erling Smørgrav auth_input_request_forwarding(struct ssh *ssh, struct passwd * pw)
18780628bacSDag-Erling Smørgrav {
18880628bacSDag-Erling Smørgrav 	Channel *nc;
189d4af9e69SDag-Erling Smørgrav 	int sock = -1;
19080628bacSDag-Erling Smørgrav 
19180628bacSDag-Erling Smørgrav 	if (auth_sock_name != NULL) {
19280628bacSDag-Erling Smørgrav 		error("authentication forwarding requested twice.");
19380628bacSDag-Erling Smørgrav 		return 0;
19480628bacSDag-Erling Smørgrav 	}
19580628bacSDag-Erling Smørgrav 
19680628bacSDag-Erling Smørgrav 	/* Temporarily drop privileged uid for mkdir/bind. */
19780628bacSDag-Erling Smørgrav 	temporarily_use_uid(pw);
19880628bacSDag-Erling Smørgrav 
19980628bacSDag-Erling Smørgrav 	/* Allocate a buffer for the socket name, and format the name. */
200d4af9e69SDag-Erling Smørgrav 	auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX");
20180628bacSDag-Erling Smørgrav 
20280628bacSDag-Erling Smørgrav 	/* Create private directory for socket */
20380628bacSDag-Erling Smørgrav 	if (mkdtemp(auth_sock_dir) == NULL) {
20419261079SEd Maste 		ssh_packet_send_debug(ssh, "Agent forwarding disabled: "
20580628bacSDag-Erling Smørgrav 		    "mkdtemp() failed: %.100s", strerror(errno));
20680628bacSDag-Erling Smørgrav 		restore_uid();
207e4a9863fSDag-Erling Smørgrav 		free(auth_sock_dir);
20880628bacSDag-Erling Smørgrav 		auth_sock_dir = NULL;
209d4af9e69SDag-Erling Smørgrav 		goto authsock_err;
21080628bacSDag-Erling Smørgrav 	}
211d4af9e69SDag-Erling Smørgrav 
212d4af9e69SDag-Erling Smørgrav 	xasprintf(&auth_sock_name, "%s/agent.%ld",
21380628bacSDag-Erling Smørgrav 	    auth_sock_dir, (long) getpid());
21480628bacSDag-Erling Smørgrav 
215a0ee8cc6SDag-Erling Smørgrav 	/* Start a Unix listener on auth_sock_name. */
216a0ee8cc6SDag-Erling Smørgrav 	sock = unix_listener(auth_sock_name, SSH_LISTEN_BACKLOG, 0);
21780628bacSDag-Erling Smørgrav 
21880628bacSDag-Erling Smørgrav 	/* Restore the privileged uid. */
21980628bacSDag-Erling Smørgrav 	restore_uid();
22080628bacSDag-Erling Smørgrav 
221a0ee8cc6SDag-Erling Smørgrav 	/* Check for socket/bind/listen failure. */
222a0ee8cc6SDag-Erling Smørgrav 	if (sock < 0)
223d4af9e69SDag-Erling Smørgrav 		goto authsock_err;
22480628bacSDag-Erling Smørgrav 
22560c59fadSDag-Erling Smørgrav 	/* Allocate a channel for the authentication agent socket. */
2264f52dfbbSDag-Erling Smørgrav 	nc = channel_new(ssh, "auth socket",
22780628bacSDag-Erling Smørgrav 	    SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,
22880628bacSDag-Erling Smørgrav 	    CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
229cf2b5f3bSDag-Erling Smørgrav 	    0, "auth socket", 1);
230cce7d346SDag-Erling Smørgrav 	nc->path = xstrdup(auth_sock_name);
23180628bacSDag-Erling Smørgrav 	return 1;
232d4af9e69SDag-Erling Smørgrav 
233d4af9e69SDag-Erling Smørgrav  authsock_err:
234e4a9863fSDag-Erling Smørgrav 	free(auth_sock_name);
235d4af9e69SDag-Erling Smørgrav 	if (auth_sock_dir != NULL) {
23619261079SEd Maste 		temporarily_use_uid(pw);
237d4af9e69SDag-Erling Smørgrav 		rmdir(auth_sock_dir);
23819261079SEd Maste 		restore_uid();
239e4a9863fSDag-Erling Smørgrav 		free(auth_sock_dir);
240d4af9e69SDag-Erling Smørgrav 	}
241d4af9e69SDag-Erling Smørgrav 	if (sock != -1)
242d4af9e69SDag-Erling Smørgrav 		close(sock);
243d4af9e69SDag-Erling Smørgrav 	auth_sock_name = NULL;
244d4af9e69SDag-Erling Smørgrav 	auth_sock_dir = NULL;
245d4af9e69SDag-Erling Smørgrav 	return 0;
24680628bacSDag-Erling Smørgrav }
24780628bacSDag-Erling Smørgrav 
2481ec0d754SDag-Erling Smørgrav static void
2491ec0d754SDag-Erling Smørgrav display_loginmsg(void)
2501ec0d754SDag-Erling Smørgrav {
251190cef3dSDag-Erling Smørgrav 	int r;
252190cef3dSDag-Erling Smørgrav 
253190cef3dSDag-Erling Smørgrav 	if (sshbuf_len(loginmsg) == 0)
254190cef3dSDag-Erling Smørgrav 		return;
255190cef3dSDag-Erling Smørgrav 	if ((r = sshbuf_put_u8(loginmsg, 0)) != 0)
25619261079SEd Maste 		fatal_fr(r, "sshbuf_put_u8");
257190cef3dSDag-Erling Smørgrav 	printf("%s", (char *)sshbuf_ptr(loginmsg));
258190cef3dSDag-Erling Smørgrav 	sshbuf_reset(loginmsg);
2591ec0d754SDag-Erling Smørgrav }
26080628bacSDag-Erling Smørgrav 
2614f52dfbbSDag-Erling Smørgrav static void
2624f52dfbbSDag-Erling Smørgrav prepare_auth_info_file(struct passwd *pw, struct sshbuf *info)
2634f52dfbbSDag-Erling Smørgrav {
2644f52dfbbSDag-Erling Smørgrav 	int fd = -1, success = 0;
2654f52dfbbSDag-Erling Smørgrav 
2664f52dfbbSDag-Erling Smørgrav 	if (!options.expose_userauth_info || info == NULL)
2674f52dfbbSDag-Erling Smørgrav 		return;
2684f52dfbbSDag-Erling Smørgrav 
2694f52dfbbSDag-Erling Smørgrav 	temporarily_use_uid(pw);
2704f52dfbbSDag-Erling Smørgrav 	auth_info_file = xstrdup("/tmp/sshauth.XXXXXXXXXXXXXXX");
2714f52dfbbSDag-Erling Smørgrav 	if ((fd = mkstemp(auth_info_file)) == -1) {
27219261079SEd Maste 		error_f("mkstemp: %s", strerror(errno));
2734f52dfbbSDag-Erling Smørgrav 		goto out;
2744f52dfbbSDag-Erling Smørgrav 	}
2754f52dfbbSDag-Erling Smørgrav 	if (atomicio(vwrite, fd, sshbuf_mutable_ptr(info),
2764f52dfbbSDag-Erling Smørgrav 	    sshbuf_len(info)) != sshbuf_len(info)) {
27719261079SEd Maste 		error_f("write: %s", strerror(errno));
2784f52dfbbSDag-Erling Smørgrav 		goto out;
2794f52dfbbSDag-Erling Smørgrav 	}
2804f52dfbbSDag-Erling Smørgrav 	if (close(fd) != 0) {
28119261079SEd Maste 		error_f("close: %s", strerror(errno));
2824f52dfbbSDag-Erling Smørgrav 		goto out;
2834f52dfbbSDag-Erling Smørgrav 	}
2844f52dfbbSDag-Erling Smørgrav 	success = 1;
2854f52dfbbSDag-Erling Smørgrav  out:
2864f52dfbbSDag-Erling Smørgrav 	if (!success) {
2874f52dfbbSDag-Erling Smørgrav 		if (fd != -1)
2884f52dfbbSDag-Erling Smørgrav 			close(fd);
2894f52dfbbSDag-Erling Smørgrav 		free(auth_info_file);
2904f52dfbbSDag-Erling Smørgrav 		auth_info_file = NULL;
2914f52dfbbSDag-Erling Smørgrav 	}
2924f52dfbbSDag-Erling Smørgrav 	restore_uid();
2934f52dfbbSDag-Erling Smørgrav }
2944f52dfbbSDag-Erling Smørgrav 
29547dd1d1bSDag-Erling Smørgrav static void
296190cef3dSDag-Erling Smørgrav set_fwdpermit_from_authopts(struct ssh *ssh, const struct sshauthopt *opts)
29747dd1d1bSDag-Erling Smørgrav {
29847dd1d1bSDag-Erling Smørgrav 	char *tmp, *cp, *host;
29947dd1d1bSDag-Erling Smørgrav 	int port;
30047dd1d1bSDag-Erling Smørgrav 	size_t i;
30147dd1d1bSDag-Erling Smørgrav 
302190cef3dSDag-Erling Smørgrav 	if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0) {
303190cef3dSDag-Erling Smørgrav 		channel_clear_permission(ssh, FORWARD_USER, FORWARD_LOCAL);
30447dd1d1bSDag-Erling Smørgrav 		for (i = 0; i < auth_opts->npermitopen; i++) {
30547dd1d1bSDag-Erling Smørgrav 			tmp = cp = xstrdup(auth_opts->permitopen[i]);
30647dd1d1bSDag-Erling Smørgrav 			/* This shouldn't fail as it has already been checked */
307*1323ec57SEd Maste 			if ((host = hpdelim2(&cp, NULL)) == NULL)
30819261079SEd Maste 				fatal_f("internal error: hpdelim");
30947dd1d1bSDag-Erling Smørgrav 			host = cleanhostname(host);
31047dd1d1bSDag-Erling Smørgrav 			if (cp == NULL || (port = permitopen_port(cp)) < 0)
31119261079SEd Maste 				fatal_f("internal error: permitopen port");
312190cef3dSDag-Erling Smørgrav 			channel_add_permission(ssh,
313190cef3dSDag-Erling Smørgrav 			    FORWARD_USER, FORWARD_LOCAL, host, port);
31447dd1d1bSDag-Erling Smørgrav 			free(tmp);
31547dd1d1bSDag-Erling Smørgrav 		}
31647dd1d1bSDag-Erling Smørgrav 	}
317190cef3dSDag-Erling Smørgrav 	if ((options.allow_tcp_forwarding & FORWARD_REMOTE) != 0) {
318190cef3dSDag-Erling Smørgrav 		channel_clear_permission(ssh, FORWARD_USER, FORWARD_REMOTE);
319190cef3dSDag-Erling Smørgrav 		for (i = 0; i < auth_opts->npermitlisten; i++) {
320190cef3dSDag-Erling Smørgrav 			tmp = cp = xstrdup(auth_opts->permitlisten[i]);
321190cef3dSDag-Erling Smørgrav 			/* This shouldn't fail as it has already been checked */
322190cef3dSDag-Erling Smørgrav 			if ((host = hpdelim(&cp)) == NULL)
32319261079SEd Maste 				fatal_f("internal error: hpdelim");
324190cef3dSDag-Erling Smørgrav 			host = cleanhostname(host);
325190cef3dSDag-Erling Smørgrav 			if (cp == NULL || (port = permitopen_port(cp)) < 0)
32619261079SEd Maste 				fatal_f("internal error: permitlisten port");
327190cef3dSDag-Erling Smørgrav 			channel_add_permission(ssh,
328190cef3dSDag-Erling Smørgrav 			    FORWARD_USER, FORWARD_REMOTE, host, port);
329190cef3dSDag-Erling Smørgrav 			free(tmp);
330190cef3dSDag-Erling Smørgrav 		}
331190cef3dSDag-Erling Smørgrav 	}
332190cef3dSDag-Erling Smørgrav }
33347dd1d1bSDag-Erling Smørgrav 
334ca3176e7SBrian Feldman void
3354f52dfbbSDag-Erling Smørgrav do_authenticated(struct ssh *ssh, Authctxt *authctxt)
336ca3176e7SBrian Feldman {
337e73e9afaSDag-Erling Smørgrav 	setproctitle("%s", authctxt->pw->pw_name);
338e73e9afaSDag-Erling Smørgrav 
33947dd1d1bSDag-Erling Smørgrav 	auth_log_authopts("active", auth_opts, 0);
34047dd1d1bSDag-Erling Smørgrav 
341ca3176e7SBrian Feldman 	/* setup the channel layer */
342a0ee8cc6SDag-Erling Smørgrav 	/* XXX - streamlocal? */
343190cef3dSDag-Erling Smørgrav 	set_fwdpermit_from_authopts(ssh, auth_opts);
344ca3176e7SBrian Feldman 
345190cef3dSDag-Erling Smørgrav 	if (!auth_opts->permit_port_forwarding_flag ||
346190cef3dSDag-Erling Smørgrav 	    options.disable_forwarding) {
347190cef3dSDag-Erling Smørgrav 		channel_disable_admin(ssh, FORWARD_LOCAL);
348190cef3dSDag-Erling Smørgrav 		channel_disable_admin(ssh, FORWARD_REMOTE);
349190cef3dSDag-Erling Smørgrav 	} else {
350190cef3dSDag-Erling Smørgrav 		if ((options.allow_tcp_forwarding & FORWARD_LOCAL) == 0)
351190cef3dSDag-Erling Smørgrav 			channel_disable_admin(ssh, FORWARD_LOCAL);
352190cef3dSDag-Erling Smørgrav 		else
353190cef3dSDag-Erling Smørgrav 			channel_permit_all(ssh, FORWARD_LOCAL);
354190cef3dSDag-Erling Smørgrav 		if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0)
355190cef3dSDag-Erling Smørgrav 			channel_disable_admin(ssh, FORWARD_REMOTE);
356190cef3dSDag-Erling Smørgrav 		else
357190cef3dSDag-Erling Smørgrav 			channel_permit_all(ssh, FORWARD_REMOTE);
358190cef3dSDag-Erling Smørgrav 	}
35919261079SEd Maste 	auth_debug_send(ssh);
360b15c8340SDag-Erling Smørgrav 
3614f52dfbbSDag-Erling Smørgrav 	prepare_auth_info_file(authctxt->pw, authctxt->session_info);
3624f52dfbbSDag-Erling Smørgrav 
3634f52dfbbSDag-Erling Smørgrav 	do_authenticated2(ssh, authctxt);
3644f52dfbbSDag-Erling Smørgrav 
3654f52dfbbSDag-Erling Smørgrav 	do_cleanup(ssh, authctxt);
366a04a10f8SKris Kennaway }
367a04a10f8SKris Kennaway 
368acc1a9efSDag-Erling Smørgrav /* Check untrusted xauth strings for metacharacters */
369acc1a9efSDag-Erling Smørgrav static int
370acc1a9efSDag-Erling Smørgrav xauth_valid_string(const char *s)
371acc1a9efSDag-Erling Smørgrav {
372acc1a9efSDag-Erling Smørgrav 	size_t i;
373acc1a9efSDag-Erling Smørgrav 
374acc1a9efSDag-Erling Smørgrav 	for (i = 0; s[i] != '\0'; i++) {
375acc1a9efSDag-Erling Smørgrav 		if (!isalnum((u_char)s[i]) &&
376acc1a9efSDag-Erling Smørgrav 		    s[i] != '.' && s[i] != ':' && s[i] != '/' &&
377acc1a9efSDag-Erling Smørgrav 		    s[i] != '-' && s[i] != '_')
378acc1a9efSDag-Erling Smørgrav 			return 0;
379acc1a9efSDag-Erling Smørgrav 	}
380acc1a9efSDag-Erling Smørgrav 	return 1;
381acc1a9efSDag-Erling Smørgrav }
382acc1a9efSDag-Erling Smørgrav 
383f7167e0eSDag-Erling Smørgrav #define USE_PIPES 1
384a04a10f8SKris Kennaway /*
385a04a10f8SKris Kennaway  * This is called to fork and execute a command when we have no tty.  This
386a04a10f8SKris Kennaway  * will call do_child from the child, and server_loop from the parent after
387a04a10f8SKris Kennaway  * setting up file descriptors and such.
388a04a10f8SKris Kennaway  */
389d4af9e69SDag-Erling Smørgrav int
3904f52dfbbSDag-Erling Smørgrav do_exec_no_pty(struct ssh *ssh, Session *s, const char *command)
391a04a10f8SKris Kennaway {
39280628bacSDag-Erling Smørgrav 	pid_t pid;
393a04a10f8SKris Kennaway #ifdef USE_PIPES
394a04a10f8SKris Kennaway 	int pin[2], pout[2], perr[2];
395d4af9e69SDag-Erling Smørgrav 
396e2f6069cSDag-Erling Smørgrav 	if (s == NULL)
397e2f6069cSDag-Erling Smørgrav 		fatal("do_exec_no_pty: no session");
398e2f6069cSDag-Erling Smørgrav 
399a04a10f8SKris Kennaway 	/* Allocate pipes for communicating with the program. */
40019261079SEd Maste 	if (pipe(pin) == -1) {
40119261079SEd Maste 		error_f("pipe in: %.100s", strerror(errno));
402d4af9e69SDag-Erling Smørgrav 		return -1;
403d4af9e69SDag-Erling Smørgrav 	}
40419261079SEd Maste 	if (pipe(pout) == -1) {
40519261079SEd Maste 		error_f("pipe out: %.100s", strerror(errno));
406d4af9e69SDag-Erling Smørgrav 		close(pin[0]);
407d4af9e69SDag-Erling Smørgrav 		close(pin[1]);
408d4af9e69SDag-Erling Smørgrav 		return -1;
409d4af9e69SDag-Erling Smørgrav 	}
41019261079SEd Maste 	if (pipe(perr) == -1) {
41119261079SEd Maste 		error_f("pipe err: %.100s", strerror(errno));
412d4af9e69SDag-Erling Smørgrav 		close(pin[0]);
413d4af9e69SDag-Erling Smørgrav 		close(pin[1]);
414d4af9e69SDag-Erling Smørgrav 		close(pout[0]);
415d4af9e69SDag-Erling Smørgrav 		close(pout[1]);
416d4af9e69SDag-Erling Smørgrav 		return -1;
417d4af9e69SDag-Erling Smørgrav 	}
418d4af9e69SDag-Erling Smørgrav #else
419a04a10f8SKris Kennaway 	int inout[2], err[2];
420d4af9e69SDag-Erling Smørgrav 
421e2f6069cSDag-Erling Smørgrav 	if (s == NULL)
422e2f6069cSDag-Erling Smørgrav 		fatal("do_exec_no_pty: no session");
423e2f6069cSDag-Erling Smørgrav 
424a04a10f8SKris Kennaway 	/* Uses socket pairs to communicate with the program. */
42519261079SEd Maste 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) {
42619261079SEd Maste 		error_f("socketpair #1: %.100s", strerror(errno));
427d4af9e69SDag-Erling Smørgrav 		return -1;
428d4af9e69SDag-Erling Smørgrav 	}
42919261079SEd Maste 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) == -1) {
43019261079SEd Maste 		error_f("socketpair #2: %.100s", strerror(errno));
431d4af9e69SDag-Erling Smørgrav 		close(inout[0]);
432d4af9e69SDag-Erling Smørgrav 		close(inout[1]);
433d4af9e69SDag-Erling Smørgrav 		return -1;
434d4af9e69SDag-Erling Smørgrav 	}
435d4af9e69SDag-Erling Smørgrav #endif
436d4af9e69SDag-Erling Smørgrav 
437a04a10f8SKris Kennaway 	session_proctitle(s);
438a04a10f8SKris Kennaway 
439a04a10f8SKris Kennaway 	/* Fork the child. */
440d4af9e69SDag-Erling Smørgrav 	switch ((pid = fork())) {
441d4af9e69SDag-Erling Smørgrav 	case -1:
44219261079SEd Maste 		error_f("fork: %.100s", strerror(errno));
443d4af9e69SDag-Erling Smørgrav #ifdef USE_PIPES
444d4af9e69SDag-Erling Smørgrav 		close(pin[0]);
445d4af9e69SDag-Erling Smørgrav 		close(pin[1]);
446d4af9e69SDag-Erling Smørgrav 		close(pout[0]);
447d4af9e69SDag-Erling Smørgrav 		close(pout[1]);
448d4af9e69SDag-Erling Smørgrav 		close(perr[0]);
449d4af9e69SDag-Erling Smørgrav 		close(perr[1]);
450d4af9e69SDag-Erling Smørgrav #else
451d4af9e69SDag-Erling Smørgrav 		close(inout[0]);
452d4af9e69SDag-Erling Smørgrav 		close(inout[1]);
453d4af9e69SDag-Erling Smørgrav 		close(err[0]);
454d4af9e69SDag-Erling Smørgrav 		close(err[1]);
455d4af9e69SDag-Erling Smørgrav #endif
456d4af9e69SDag-Erling Smørgrav 		return -1;
457d4af9e69SDag-Erling Smørgrav 	case 0:
4581ec0d754SDag-Erling Smørgrav 		is_child = 1;
459f388f5efSDag-Erling Smørgrav 
460a04a10f8SKris Kennaway 		/*
461a04a10f8SKris Kennaway 		 * Create a new session and process group since the 4.4BSD
462a04a10f8SKris Kennaway 		 * setlogin() affects the entire process group.
463a04a10f8SKris Kennaway 		 */
46419261079SEd Maste 		if (setsid() == -1)
465a04a10f8SKris Kennaway 			error("setsid failed: %.100s", strerror(errno));
466a04a10f8SKris Kennaway 
467a04a10f8SKris Kennaway #ifdef USE_PIPES
468a04a10f8SKris Kennaway 		/*
469a04a10f8SKris Kennaway 		 * Redirect stdin.  We close the parent side of the socket
470a04a10f8SKris Kennaway 		 * pair, and make the child side the standard input.
471a04a10f8SKris Kennaway 		 */
472a04a10f8SKris Kennaway 		close(pin[1]);
47319261079SEd Maste 		if (dup2(pin[0], 0) == -1)
474a04a10f8SKris Kennaway 			perror("dup2 stdin");
475a04a10f8SKris Kennaway 		close(pin[0]);
476a04a10f8SKris Kennaway 
477a04a10f8SKris Kennaway 		/* Redirect stdout. */
478a04a10f8SKris Kennaway 		close(pout[0]);
47919261079SEd Maste 		if (dup2(pout[1], 1) == -1)
480a04a10f8SKris Kennaway 			perror("dup2 stdout");
481a04a10f8SKris Kennaway 		close(pout[1]);
482a04a10f8SKris Kennaway 
483a04a10f8SKris Kennaway 		/* Redirect stderr. */
484a04a10f8SKris Kennaway 		close(perr[0]);
48519261079SEd Maste 		if (dup2(perr[1], 2) == -1)
486a04a10f8SKris Kennaway 			perror("dup2 stderr");
487a04a10f8SKris Kennaway 		close(perr[1]);
488d4af9e69SDag-Erling Smørgrav #else
489a04a10f8SKris Kennaway 		/*
490a04a10f8SKris Kennaway 		 * Redirect stdin, stdout, and stderr.  Stdin and stdout will
491a04a10f8SKris Kennaway 		 * use the same socket, as some programs (particularly rdist)
492a04a10f8SKris Kennaway 		 * seem to depend on it.
493a04a10f8SKris Kennaway 		 */
494a04a10f8SKris Kennaway 		close(inout[1]);
495a04a10f8SKris Kennaway 		close(err[1]);
49619261079SEd Maste 		if (dup2(inout[0], 0) == -1)	/* stdin */
497a04a10f8SKris Kennaway 			perror("dup2 stdin");
49819261079SEd Maste 		if (dup2(inout[0], 1) == -1)	/* stdout (same as stdin) */
499a04a10f8SKris Kennaway 			perror("dup2 stdout");
500d4af9e69SDag-Erling Smørgrav 		close(inout[0]);
50119261079SEd Maste 		if (dup2(err[0], 2) == -1)	/* stderr */
502a04a10f8SKris Kennaway 			perror("dup2 stderr");
503d4af9e69SDag-Erling Smørgrav 		close(err[0]);
504d4af9e69SDag-Erling Smørgrav #endif
505d4af9e69SDag-Erling Smørgrav 
506a04a10f8SKris Kennaway 		/* Do processing for the child (exec command etc). */
5074f52dfbbSDag-Erling Smørgrav 		do_child(ssh, s, command);
508a04a10f8SKris Kennaway 		/* NOTREACHED */
509d4af9e69SDag-Erling Smørgrav 	default:
510d4af9e69SDag-Erling Smørgrav 		break;
511a04a10f8SKris Kennaway 	}
512d4af9e69SDag-Erling Smørgrav 
513989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN
514989dd127SDag-Erling Smørgrav 	cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
515989dd127SDag-Erling Smørgrav #endif
516d4af9e69SDag-Erling Smørgrav 
517a04a10f8SKris Kennaway 	s->pid = pid;
518ca3176e7SBrian Feldman 	/* Set interactive/non-interactive mode. */
51919261079SEd Maste 	ssh_packet_set_interactive(ssh, s->display != NULL,
5204a421b63SDag-Erling Smørgrav 	    options.ip_qos_interactive, options.ip_qos_bulk);
521d4af9e69SDag-Erling Smørgrav 
522d4af9e69SDag-Erling Smørgrav 	/*
523d4af9e69SDag-Erling Smørgrav 	 * Clear loginmsg, since it's the child's responsibility to display
524d4af9e69SDag-Erling Smørgrav 	 * it to the user, otherwise multiple sessions may accumulate
525d4af9e69SDag-Erling Smørgrav 	 * multiple copies of the login messages.
526d4af9e69SDag-Erling Smørgrav 	 */
527190cef3dSDag-Erling Smørgrav 	sshbuf_reset(loginmsg);
528d4af9e69SDag-Erling Smørgrav 
529a04a10f8SKris Kennaway #ifdef USE_PIPES
530a04a10f8SKris Kennaway 	/* We are the parent.  Close the child sides of the pipes. */
531a04a10f8SKris Kennaway 	close(pin[0]);
532a04a10f8SKris Kennaway 	close(pout[1]);
533a04a10f8SKris Kennaway 	close(perr[1]);
534a04a10f8SKris Kennaway 
5354f52dfbbSDag-Erling Smørgrav 	session_set_fds(ssh, s, pin[1], pout[0], perr[0],
536e2f6069cSDag-Erling Smørgrav 	    s->is_subsystem, 0);
537d4af9e69SDag-Erling Smørgrav #else
538a04a10f8SKris Kennaway 	/* We are the parent.  Close the child sides of the socket pairs. */
539a04a10f8SKris Kennaway 	close(inout[0]);
540a04a10f8SKris Kennaway 	close(err[0]);
541a04a10f8SKris Kennaway 
542a04a10f8SKris Kennaway 	/*
543a04a10f8SKris Kennaway 	 * Enter the interactive session.  Note: server_loop must be able to
544a04a10f8SKris Kennaway 	 * handle the case that fdin and fdout are the same.
545a04a10f8SKris Kennaway 	 */
54619261079SEd Maste 	session_set_fds(ssh, s, inout[1], inout[1], err[1],
547e2f6069cSDag-Erling Smørgrav 	    s->is_subsystem, 0);
548d4af9e69SDag-Erling Smørgrav #endif
549d4af9e69SDag-Erling Smørgrav 	return 0;
550a04a10f8SKris Kennaway }
551a04a10f8SKris Kennaway 
552a04a10f8SKris Kennaway /*
553a04a10f8SKris Kennaway  * This is called to fork and execute a command when we have a tty.  This
554a04a10f8SKris Kennaway  * will call do_child from the child, and server_loop from the parent after
555a04a10f8SKris Kennaway  * setting up file descriptors, controlling tty, updating wtmp, utmp,
556a04a10f8SKris Kennaway  * lastlog, and other such operations.
557a04a10f8SKris Kennaway  */
558d4af9e69SDag-Erling Smørgrav int
5594f52dfbbSDag-Erling Smørgrav do_exec_pty(struct ssh *ssh, Session *s, const char *command)
560a04a10f8SKris Kennaway {
561a04a10f8SKris Kennaway 	int fdout, ptyfd, ttyfd, ptymaster;
562a04a10f8SKris Kennaway 	pid_t pid;
563a04a10f8SKris Kennaway 
564a04a10f8SKris Kennaway 	if (s == NULL)
565a04a10f8SKris Kennaway 		fatal("do_exec_pty: no session");
566a04a10f8SKris Kennaway 	ptyfd = s->ptyfd;
567a04a10f8SKris Kennaway 	ttyfd = s->ttyfd;
568a04a10f8SKris Kennaway 
569d4af9e69SDag-Erling Smørgrav 	/*
570d4af9e69SDag-Erling Smørgrav 	 * Create another descriptor of the pty master side for use as the
571d4af9e69SDag-Erling Smørgrav 	 * standard input.  We could use the original descriptor, but this
572d4af9e69SDag-Erling Smørgrav 	 * simplifies code in server_loop.  The descriptor is bidirectional.
573d4af9e69SDag-Erling Smørgrav 	 * Do this before forking (and cleanup in the child) so as to
574d4af9e69SDag-Erling Smørgrav 	 * detect and gracefully fail out-of-fd conditions.
575d4af9e69SDag-Erling Smørgrav 	 */
57619261079SEd Maste 	if ((fdout = dup(ptyfd)) == -1) {
57719261079SEd Maste 		error_f("dup #1: %s", strerror(errno));
578d4af9e69SDag-Erling Smørgrav 		close(ttyfd);
579d4af9e69SDag-Erling Smørgrav 		close(ptyfd);
580d4af9e69SDag-Erling Smørgrav 		return -1;
581cf2b5f3bSDag-Erling Smørgrav 	}
582d4af9e69SDag-Erling Smørgrav 	/* we keep a reference to the pty master */
58319261079SEd Maste 	if ((ptymaster = dup(ptyfd)) == -1) {
58419261079SEd Maste 		error_f("dup #2: %s", strerror(errno));
585d4af9e69SDag-Erling Smørgrav 		close(ttyfd);
586d4af9e69SDag-Erling Smørgrav 		close(ptyfd);
587d4af9e69SDag-Erling Smørgrav 		close(fdout);
588d4af9e69SDag-Erling Smørgrav 		return -1;
589d4af9e69SDag-Erling Smørgrav 	}
59009958426SBrian Feldman 
591a04a10f8SKris Kennaway 	/* Fork the child. */
592d4af9e69SDag-Erling Smørgrav 	switch ((pid = fork())) {
593d4af9e69SDag-Erling Smørgrav 	case -1:
59419261079SEd Maste 		error_f("fork: %.100s", strerror(errno));
595d4af9e69SDag-Erling Smørgrav 		close(fdout);
596d4af9e69SDag-Erling Smørgrav 		close(ptymaster);
597d4af9e69SDag-Erling Smørgrav 		close(ttyfd);
598d4af9e69SDag-Erling Smørgrav 		close(ptyfd);
599d4af9e69SDag-Erling Smørgrav 		return -1;
600d4af9e69SDag-Erling Smørgrav 	case 0:
6011ec0d754SDag-Erling Smørgrav 		is_child = 1;
602af12a3e7SDag-Erling Smørgrav 
603d4af9e69SDag-Erling Smørgrav 		close(fdout);
604d4af9e69SDag-Erling Smørgrav 		close(ptymaster);
605d4af9e69SDag-Erling Smørgrav 
606a04a10f8SKris Kennaway 		/* Close the master side of the pseudo tty. */
607a04a10f8SKris Kennaway 		close(ptyfd);
608a04a10f8SKris Kennaway 
609a04a10f8SKris Kennaway 		/* Make the pseudo tty our controlling tty. */
610a04a10f8SKris Kennaway 		pty_make_controlling_tty(&ttyfd, s->tty);
611a04a10f8SKris Kennaway 
612af12a3e7SDag-Erling Smørgrav 		/* Redirect stdin/stdout/stderr from the pseudo tty. */
61319261079SEd Maste 		if (dup2(ttyfd, 0) == -1)
614af12a3e7SDag-Erling Smørgrav 			error("dup2 stdin: %s", strerror(errno));
61519261079SEd Maste 		if (dup2(ttyfd, 1) == -1)
616af12a3e7SDag-Erling Smørgrav 			error("dup2 stdout: %s", strerror(errno));
61719261079SEd Maste 		if (dup2(ttyfd, 2) == -1)
618af12a3e7SDag-Erling Smørgrav 			error("dup2 stderr: %s", strerror(errno));
619a04a10f8SKris Kennaway 
620a04a10f8SKris Kennaway 		/* Close the extra descriptor for the pseudo tty. */
621a04a10f8SKris Kennaway 		close(ttyfd);
622a04a10f8SKris Kennaway 
623c2d3a559SKris Kennaway 		/* record login, etc. similar to login(1) */
624ca86bcf2SDag-Erling Smørgrav #ifndef HAVE_OSF_SIA
6254f52dfbbSDag-Erling Smørgrav 		do_login(ssh, s, command);
626989dd127SDag-Erling Smørgrav #endif
627d4af9e69SDag-Erling Smørgrav 		/*
628d4af9e69SDag-Erling Smørgrav 		 * Do common processing for the child, such as execing
629d4af9e69SDag-Erling Smørgrav 		 * the command.
630d4af9e69SDag-Erling Smørgrav 		 */
6314f52dfbbSDag-Erling Smørgrav 		do_child(ssh, s, command);
632a04a10f8SKris Kennaway 		/* NOTREACHED */
633d4af9e69SDag-Erling Smørgrav 	default:
634d4af9e69SDag-Erling Smørgrav 		break;
635a04a10f8SKris Kennaway 	}
636d4af9e69SDag-Erling Smørgrav 
637989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN
638989dd127SDag-Erling Smørgrav 	cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
639989dd127SDag-Erling Smørgrav #endif
640d4af9e69SDag-Erling Smørgrav 
641a04a10f8SKris Kennaway 	s->pid = pid;
642a04a10f8SKris Kennaway 
643a04a10f8SKris Kennaway 	/* Parent.  Close the slave side of the pseudo tty. */
644a04a10f8SKris Kennaway 	close(ttyfd);
645a04a10f8SKris Kennaway 
646a04a10f8SKris Kennaway 	/* Enter interactive session. */
647d4af9e69SDag-Erling Smørgrav 	s->ptymaster = ptymaster;
64819261079SEd Maste 	ssh_packet_set_interactive(ssh, 1,
6494a421b63SDag-Erling Smørgrav 	    options.ip_qos_interactive, options.ip_qos_bulk);
6504f52dfbbSDag-Erling Smørgrav 	session_set_fds(ssh, s, ptyfd, fdout, -1, 1, 1);
651d4af9e69SDag-Erling Smørgrav 	return 0;
652a04a10f8SKris Kennaway }
653a04a10f8SKris Kennaway 
654af12a3e7SDag-Erling Smørgrav /*
655af12a3e7SDag-Erling Smørgrav  * This is called to fork and execute a command.  If another command is
656af12a3e7SDag-Erling Smørgrav  * to be forced, execute that instead.
657af12a3e7SDag-Erling Smørgrav  */
658d4af9e69SDag-Erling Smørgrav int
6594f52dfbbSDag-Erling Smørgrav do_exec(struct ssh *ssh, Session *s, const char *command)
660af12a3e7SDag-Erling Smørgrav {
661d4af9e69SDag-Erling Smørgrav 	int ret;
662acc1a9efSDag-Erling Smørgrav 	const char *forced = NULL, *tty = NULL;
663acc1a9efSDag-Erling Smørgrav 	char session_type[1024];
664d4af9e69SDag-Erling Smørgrav 
665333ee039SDag-Erling Smørgrav 	if (options.adm_forced_command) {
666333ee039SDag-Erling Smørgrav 		original_command = command;
667333ee039SDag-Erling Smørgrav 		command = options.adm_forced_command;
668f7167e0eSDag-Erling Smørgrav 		forced = "(config)";
66947dd1d1bSDag-Erling Smørgrav 	} else if (auth_opts->force_command != NULL) {
670af12a3e7SDag-Erling Smørgrav 		original_command = command;
67147dd1d1bSDag-Erling Smørgrav 		command = auth_opts->force_command;
672f7167e0eSDag-Erling Smørgrav 		forced = "(key-option)";
673f7167e0eSDag-Erling Smørgrav 	}
6742f513db7SEd Maste 	s->forced = 0;
675f7167e0eSDag-Erling Smørgrav 	if (forced != NULL) {
6762f513db7SEd Maste 		s->forced = 1;
677b15c8340SDag-Erling Smørgrav 		if (IS_INTERNAL_SFTP(command)) {
678b15c8340SDag-Erling Smørgrav 			s->is_subsystem = s->is_subsystem ?
679b15c8340SDag-Erling Smørgrav 			    SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR;
680b15c8340SDag-Erling Smørgrav 		} else if (s->is_subsystem)
681d4af9e69SDag-Erling Smørgrav 			s->is_subsystem = SUBSYSTEM_EXT;
682f7167e0eSDag-Erling Smørgrav 		snprintf(session_type, sizeof(session_type),
683f7167e0eSDag-Erling Smørgrav 		    "forced-command %s '%.900s'", forced, command);
684f7167e0eSDag-Erling Smørgrav 	} else if (s->is_subsystem) {
685f7167e0eSDag-Erling Smørgrav 		snprintf(session_type, sizeof(session_type),
686f7167e0eSDag-Erling Smørgrav 		    "subsystem '%.900s'", s->subsys);
687f7167e0eSDag-Erling Smørgrav 	} else if (command == NULL) {
688f7167e0eSDag-Erling Smørgrav 		snprintf(session_type, sizeof(session_type), "shell");
689f7167e0eSDag-Erling Smørgrav 	} else {
690f7167e0eSDag-Erling Smørgrav 		/* NB. we don't log unforced commands to preserve privacy */
691f7167e0eSDag-Erling Smørgrav 		snprintf(session_type, sizeof(session_type), "command");
692af12a3e7SDag-Erling Smørgrav 	}
693af12a3e7SDag-Erling Smørgrav 
694f7167e0eSDag-Erling Smørgrav 	if (s->ttyfd != -1) {
695f7167e0eSDag-Erling Smørgrav 		tty = s->tty;
696f7167e0eSDag-Erling Smørgrav 		if (strncmp(tty, "/dev/", 5) == 0)
697f7167e0eSDag-Erling Smørgrav 			tty += 5;
698f7167e0eSDag-Erling Smørgrav 	}
699f7167e0eSDag-Erling Smørgrav 
700acc1a9efSDag-Erling Smørgrav 	verbose("Starting session: %s%s%s for %s from %.200s port %d id %d",
701f7167e0eSDag-Erling Smørgrav 	    session_type,
702f7167e0eSDag-Erling Smørgrav 	    tty == NULL ? "" : " on ",
703f7167e0eSDag-Erling Smørgrav 	    tty == NULL ? "" : tty,
704f7167e0eSDag-Erling Smørgrav 	    s->pw->pw_name,
705076ad2f8SDag-Erling Smørgrav 	    ssh_remote_ipaddr(ssh),
706076ad2f8SDag-Erling Smørgrav 	    ssh_remote_port(ssh),
707acc1a9efSDag-Erling Smørgrav 	    s->self);
708f7167e0eSDag-Erling Smørgrav 
709aa49c926SDag-Erling Smørgrav #ifdef SSH_AUDIT_EVENTS
710aa49c926SDag-Erling Smørgrav 	if (command != NULL)
711aa49c926SDag-Erling Smørgrav 		PRIVSEP(audit_run_command(command));
712aa49c926SDag-Erling Smørgrav 	else if (s->ttyfd == -1) {
713aa49c926SDag-Erling Smørgrav 		char *shell = s->pw->pw_shell;
714aa49c926SDag-Erling Smørgrav 
715aa49c926SDag-Erling Smørgrav 		if (shell[0] == '\0')	/* empty shell means /bin/sh */
716aa49c926SDag-Erling Smørgrav 			shell =_PATH_BSHELL;
717aa49c926SDag-Erling Smørgrav 		PRIVSEP(audit_run_command(shell));
718cf2b5f3bSDag-Erling Smørgrav 	}
719cf2b5f3bSDag-Erling Smørgrav #endif
720af12a3e7SDag-Erling Smørgrav 	if (s->ttyfd != -1)
7214f52dfbbSDag-Erling Smørgrav 		ret = do_exec_pty(ssh, s, command);
722af12a3e7SDag-Erling Smørgrav 	else
7234f52dfbbSDag-Erling Smørgrav 		ret = do_exec_no_pty(ssh, s, command);
724af12a3e7SDag-Erling Smørgrav 
725af12a3e7SDag-Erling Smørgrav 	original_command = NULL;
726af12a3e7SDag-Erling Smørgrav 
72721e764dfSDag-Erling Smørgrav 	/*
72821e764dfSDag-Erling Smørgrav 	 * Clear loginmsg: it's the child's responsibility to display
72921e764dfSDag-Erling Smørgrav 	 * it to the user, otherwise multiple sessions may accumulate
73021e764dfSDag-Erling Smørgrav 	 * multiple copies of the login messages.
73121e764dfSDag-Erling Smørgrav 	 */
732190cef3dSDag-Erling Smørgrav 	sshbuf_reset(loginmsg);
733d4af9e69SDag-Erling Smørgrav 
734d4af9e69SDag-Erling Smørgrav 	return ret;
73521e764dfSDag-Erling Smørgrav }
736af12a3e7SDag-Erling Smørgrav 
737c2d3a559SKris Kennaway /* administrative, login(1)-like work */
738ca3176e7SBrian Feldman void
7394f52dfbbSDag-Erling Smørgrav do_login(struct ssh *ssh, Session *s, const char *command)
740c2d3a559SKris Kennaway {
741c2d3a559SKris Kennaway 	socklen_t fromlen;
742c2d3a559SKris Kennaway 	struct sockaddr_storage from;
743c2d3a559SKris Kennaway 	struct passwd * pw = s->pw;
744c2d3a559SKris Kennaway 	pid_t pid = getpid();
745c2d3a559SKris Kennaway 
746c2d3a559SKris Kennaway 	/*
747c2d3a559SKris Kennaway 	 * Get IP address of client. If the connection is not a socket, let
748c2d3a559SKris Kennaway 	 * the address be 0.0.0.0.
749c2d3a559SKris Kennaway 	 */
750c2d3a559SKris Kennaway 	memset(&from, 0, sizeof(from));
751c2d3a559SKris Kennaway 	fromlen = sizeof(from);
75219261079SEd Maste 	if (ssh_packet_connection_is_on_socket(ssh)) {
75319261079SEd Maste 		if (getpeername(ssh_packet_get_connection_in(ssh),
75419261079SEd Maste 		    (struct sockaddr *)&from, &fromlen) == -1) {
755c2d3a559SKris Kennaway 			debug("getpeername: %.100s", strerror(errno));
7561ec0d754SDag-Erling Smørgrav 			cleanup_exit(255);
757c2d3a559SKris Kennaway 		}
758c2d3a559SKris Kennaway 	}
759c2d3a559SKris Kennaway 
76080628bacSDag-Erling Smørgrav 	/* Record that there was a login on that tty from the remote host. */
76180628bacSDag-Erling Smørgrav 	if (!use_privsep)
76280628bacSDag-Erling Smørgrav 		record_login(pid, s->tty, pw->pw_name, pw->pw_uid,
763076ad2f8SDag-Erling Smørgrav 		    session_get_remote_name_or_ip(ssh, utmp_len,
764cf2b5f3bSDag-Erling Smørgrav 		    options.use_dns),
7657ac32603SHajimu UMEMOTO 		    (struct sockaddr *)&from, fromlen);
76680628bacSDag-Erling Smørgrav 
767098de0c1SAndrey A. Chernov #ifdef USE_PAM
768c2d3a559SKris Kennaway 	/*
769989dd127SDag-Erling Smørgrav 	 * If password change is needed, do it now.
770989dd127SDag-Erling Smørgrav 	 * This needs to occur before the ~/.hushlogin check.
771c2d3a559SKris Kennaway 	 */
7721ec0d754SDag-Erling Smørgrav 	if (options.use_pam && !use_privsep && s->authctxt->force_pwchange) {
7731ec0d754SDag-Erling Smørgrav 		display_loginmsg();
774989dd127SDag-Erling Smørgrav 		do_pam_chauthtok();
7751ec0d754SDag-Erling Smørgrav 		s->authctxt->force_pwchange = 0;
776cf2b5f3bSDag-Erling Smørgrav 		/* XXX - signal [net] parent to enable forwardings */
777989dd127SDag-Erling Smørgrav 	}
778989dd127SDag-Erling Smørgrav #endif
779af12a3e7SDag-Erling Smørgrav 
780989dd127SDag-Erling Smørgrav 	if (check_quietlogin(s, command))
781989dd127SDag-Erling Smørgrav 		return;
782989dd127SDag-Erling Smørgrav 
7831ec0d754SDag-Erling Smørgrav 	display_loginmsg();
784f388f5efSDag-Erling Smørgrav 
785ca3176e7SBrian Feldman 	do_motd();
786ca3176e7SBrian Feldman }
787ca3176e7SBrian Feldman 
788ca3176e7SBrian Feldman /*
789ca3176e7SBrian Feldman  * Display the message of the day.
790ca3176e7SBrian Feldman  */
791ca3176e7SBrian Feldman void
792ca3176e7SBrian Feldman do_motd(void)
793ca3176e7SBrian Feldman {
794ca3176e7SBrian Feldman 	FILE *f;
795ca3176e7SBrian Feldman 	char buf[256];
796ca3176e7SBrian Feldman 
797ca3176e7SBrian Feldman 	if (options.print_motd) {
798c2d3a559SKris Kennaway #ifdef HAVE_LOGIN_CAP
799c2d3a559SKris Kennaway 		f = fopen(login_getcapstr(lc, "welcome", "/etc/motd",
800c2d3a559SKris Kennaway 		    "/etc/motd"), "r");
801af12a3e7SDag-Erling Smørgrav #else
802c2d3a559SKris Kennaway 		f = fopen("/etc/motd", "r");
803af12a3e7SDag-Erling Smørgrav #endif
804c2d3a559SKris Kennaway 		if (f) {
805c2d3a559SKris Kennaway 			while (fgets(buf, sizeof(buf), f))
806c2d3a559SKris Kennaway 				fputs(buf, stdout);
807c2d3a559SKris Kennaway 			fclose(f);
808c2d3a559SKris Kennaway 		}
809c2d3a559SKris Kennaway 	}
810ca3176e7SBrian Feldman }
811c2d3a559SKris Kennaway 
812af12a3e7SDag-Erling Smørgrav 
813ca3176e7SBrian Feldman /*
814ca3176e7SBrian Feldman  * Check for quiet login, either .hushlogin or command given.
815ca3176e7SBrian Feldman  */
816ca3176e7SBrian Feldman int
817ca3176e7SBrian Feldman check_quietlogin(Session *s, const char *command)
818ca3176e7SBrian Feldman {
819ca3176e7SBrian Feldman 	char buf[256];
820ca3176e7SBrian Feldman 	struct passwd *pw = s->pw;
821ca3176e7SBrian Feldman 	struct stat st;
822ca3176e7SBrian Feldman 
823ca3176e7SBrian Feldman 	/* Return 1 if .hushlogin exists or a command given. */
824ca3176e7SBrian Feldman 	if (command != NULL)
825ca3176e7SBrian Feldman 		return 1;
826ca3176e7SBrian Feldman 	snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir);
827c2d3a559SKris Kennaway #ifdef HAVE_LOGIN_CAP
828ca3176e7SBrian Feldman 	if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0)
829ca3176e7SBrian Feldman 		return 1;
830ca3176e7SBrian Feldman #else
831ca3176e7SBrian Feldman 	if (stat(buf, &st) >= 0)
832ca3176e7SBrian Feldman 		return 1;
833ca3176e7SBrian Feldman #endif
834ca3176e7SBrian Feldman 	return 0;
835c2d3a559SKris Kennaway }
836c2d3a559SKris Kennaway 
837a04a10f8SKris Kennaway /*
838a04a10f8SKris Kennaway  * Reads environment variables from the given file and adds/overrides them
839a04a10f8SKris Kennaway  * into the environment.  If the file does not exist, this does nothing.
840a04a10f8SKris Kennaway  * Otherwise, it must consist of empty lines, comments (line starts with '#')
841a04a10f8SKris Kennaway  * and assignments of the form name=value.  No other forms are allowed.
84219261079SEd Maste  * If allowlist is not NULL, then it is interpreted as a pattern list and
843190cef3dSDag-Erling Smørgrav  * only variable names that match it will be accepted.
844a04a10f8SKris Kennaway  */
845af12a3e7SDag-Erling Smørgrav static void
846ca3176e7SBrian Feldman read_environment_file(char ***env, u_int *envsize,
84719261079SEd Maste 	const char *filename, const char *allowlist)
848a04a10f8SKris Kennaway {
849a04a10f8SKris Kennaway 	FILE *f;
850190cef3dSDag-Erling Smørgrav 	char *line = NULL, *cp, *value;
851190cef3dSDag-Erling Smørgrav 	size_t linesize = 0;
852a82e551fSDag-Erling Smørgrav 	u_int lineno = 0;
853a04a10f8SKris Kennaway 
854a04a10f8SKris Kennaway 	f = fopen(filename, "r");
855a04a10f8SKris Kennaway 	if (!f)
856a04a10f8SKris Kennaway 		return;
857a04a10f8SKris Kennaway 
858190cef3dSDag-Erling Smørgrav 	while (getline(&line, &linesize, f) != -1) {
859a82e551fSDag-Erling Smørgrav 		if (++lineno > 1000)
860a82e551fSDag-Erling Smørgrav 			fatal("Too many lines in environment file %s", filename);
861190cef3dSDag-Erling Smørgrav 		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
862a04a10f8SKris Kennaway 			;
863a04a10f8SKris Kennaway 		if (!*cp || *cp == '#' || *cp == '\n')
864a04a10f8SKris Kennaway 			continue;
865d4af9e69SDag-Erling Smørgrav 
866d4af9e69SDag-Erling Smørgrav 		cp[strcspn(cp, "\n")] = '\0';
867d4af9e69SDag-Erling Smørgrav 
868a04a10f8SKris Kennaway 		value = strchr(cp, '=');
869a04a10f8SKris Kennaway 		if (value == NULL) {
870a82e551fSDag-Erling Smørgrav 			fprintf(stderr, "Bad line %u in %.100s\n", lineno,
871a82e551fSDag-Erling Smørgrav 			    filename);
872a04a10f8SKris Kennaway 			continue;
873a04a10f8SKris Kennaway 		}
874db1cb46cSKris Kennaway 		/*
875db1cb46cSKris Kennaway 		 * Replace the equals sign by nul, and advance value to
876db1cb46cSKris Kennaway 		 * the value string.
877db1cb46cSKris Kennaway 		 */
878a04a10f8SKris Kennaway 		*value = '\0';
879a04a10f8SKris Kennaway 		value++;
88019261079SEd Maste 		if (allowlist != NULL &&
88119261079SEd Maste 		    match_pattern_list(cp, allowlist, 0) != 1)
882190cef3dSDag-Erling Smørgrav 			continue;
883a04a10f8SKris Kennaway 		child_set_env(env, envsize, cp, value);
884a04a10f8SKris Kennaway 	}
885190cef3dSDag-Erling Smørgrav 	free(line);
886a04a10f8SKris Kennaway 	fclose(f);
887a04a10f8SKris Kennaway }
888a04a10f8SKris Kennaway 
889cf2b5f3bSDag-Erling Smørgrav #ifdef HAVE_ETC_DEFAULT_LOGIN
890cf2b5f3bSDag-Erling Smørgrav /*
891cf2b5f3bSDag-Erling Smørgrav  * Return named variable from specified environment, or NULL if not present.
892cf2b5f3bSDag-Erling Smørgrav  */
893cf2b5f3bSDag-Erling Smørgrav static char *
894cf2b5f3bSDag-Erling Smørgrav child_get_env(char **env, const char *name)
895cf2b5f3bSDag-Erling Smørgrav {
896cf2b5f3bSDag-Erling Smørgrav 	int i;
897cf2b5f3bSDag-Erling Smørgrav 	size_t len;
898cf2b5f3bSDag-Erling Smørgrav 
899cf2b5f3bSDag-Erling Smørgrav 	len = strlen(name);
900cf2b5f3bSDag-Erling Smørgrav 	for (i=0; env[i] != NULL; i++)
901cf2b5f3bSDag-Erling Smørgrav 		if (strncmp(name, env[i], len) == 0 && env[i][len] == '=')
902cf2b5f3bSDag-Erling Smørgrav 			return(env[i] + len + 1);
903cf2b5f3bSDag-Erling Smørgrav 	return NULL;
904cf2b5f3bSDag-Erling Smørgrav }
905cf2b5f3bSDag-Erling Smørgrav 
906cf2b5f3bSDag-Erling Smørgrav /*
907cf2b5f3bSDag-Erling Smørgrav  * Read /etc/default/login.
908cf2b5f3bSDag-Erling Smørgrav  * We pick up the PATH (or SUPATH for root) and UMASK.
909cf2b5f3bSDag-Erling Smørgrav  */
910cf2b5f3bSDag-Erling Smørgrav static void
911cf2b5f3bSDag-Erling Smørgrav read_etc_default_login(char ***env, u_int *envsize, uid_t uid)
912cf2b5f3bSDag-Erling Smørgrav {
913cf2b5f3bSDag-Erling Smørgrav 	char **tmpenv = NULL, *var;
914cf2b5f3bSDag-Erling Smørgrav 	u_int i, tmpenvsize = 0;
9151ec0d754SDag-Erling Smørgrav 	u_long mask;
916cf2b5f3bSDag-Erling Smørgrav 
917cf2b5f3bSDag-Erling Smørgrav 	/*
918cf2b5f3bSDag-Erling Smørgrav 	 * We don't want to copy the whole file to the child's environment,
919cf2b5f3bSDag-Erling Smørgrav 	 * so we use a temporary environment and copy the variables we're
920cf2b5f3bSDag-Erling Smørgrav 	 * interested in.
921cf2b5f3bSDag-Erling Smørgrav 	 */
922190cef3dSDag-Erling Smørgrav 	read_environment_file(&tmpenv, &tmpenvsize, "/etc/default/login",
92319261079SEd Maste 	    options.permit_user_env_allowlist);
924cf2b5f3bSDag-Erling Smørgrav 
925cf2b5f3bSDag-Erling Smørgrav 	if (tmpenv == NULL)
926cf2b5f3bSDag-Erling Smørgrav 		return;
927cf2b5f3bSDag-Erling Smørgrav 
928cf2b5f3bSDag-Erling Smørgrav 	if (uid == 0)
929cf2b5f3bSDag-Erling Smørgrav 		var = child_get_env(tmpenv, "SUPATH");
930cf2b5f3bSDag-Erling Smørgrav 	else
931cf2b5f3bSDag-Erling Smørgrav 		var = child_get_env(tmpenv, "PATH");
932cf2b5f3bSDag-Erling Smørgrav 	if (var != NULL)
933cf2b5f3bSDag-Erling Smørgrav 		child_set_env(env, envsize, "PATH", var);
934cf2b5f3bSDag-Erling Smørgrav 
935cf2b5f3bSDag-Erling Smørgrav 	if ((var = child_get_env(tmpenv, "UMASK")) != NULL)
936cf2b5f3bSDag-Erling Smørgrav 		if (sscanf(var, "%5lo", &mask) == 1)
9371ec0d754SDag-Erling Smørgrav 			umask((mode_t)mask);
938cf2b5f3bSDag-Erling Smørgrav 
939cf2b5f3bSDag-Erling Smørgrav 	for (i = 0; tmpenv[i] != NULL; i++)
940e4a9863fSDag-Erling Smørgrav 		free(tmpenv[i]);
941e4a9863fSDag-Erling Smørgrav 	free(tmpenv);
942cf2b5f3bSDag-Erling Smørgrav }
943cf2b5f3bSDag-Erling Smørgrav #endif /* HAVE_ETC_DEFAULT_LOGIN */
944cf2b5f3bSDag-Erling Smørgrav 
94519261079SEd Maste #if defined(USE_PAM) || defined(HAVE_CYGWIN)
9464f52dfbbSDag-Erling Smørgrav static void
94719261079SEd Maste copy_environment_denylist(char **source, char ***env, u_int *envsize,
94819261079SEd Maste     const char *denylist)
94909958426SBrian Feldman {
950989dd127SDag-Erling Smørgrav 	char *var_name, *var_val;
95109958426SBrian Feldman 	int i;
95209958426SBrian Feldman 
953989dd127SDag-Erling Smørgrav 	if (source == NULL)
95409958426SBrian Feldman 		return;
95509958426SBrian Feldman 
956989dd127SDag-Erling Smørgrav 	for(i = 0; source[i] != NULL; i++) {
957989dd127SDag-Erling Smørgrav 		var_name = xstrdup(source[i]);
958989dd127SDag-Erling Smørgrav 		if ((var_val = strstr(var_name, "=")) == NULL) {
959e4a9863fSDag-Erling Smørgrav 			free(var_name);
96009958426SBrian Feldman 			continue;
961989dd127SDag-Erling Smørgrav 		}
962989dd127SDag-Erling Smørgrav 		*var_val++ = '\0';
96309958426SBrian Feldman 
96419261079SEd Maste 		if (denylist == NULL ||
96519261079SEd Maste 		    match_pattern_list(var_name, denylist, 0) != 1) {
966989dd127SDag-Erling Smørgrav 			debug3("Copy environment: %s=%s", var_name, var_val);
96709958426SBrian Feldman 			child_set_env(env, envsize, var_name, var_val);
9684f52dfbbSDag-Erling Smørgrav 		}
969989dd127SDag-Erling Smørgrav 
970e4a9863fSDag-Erling Smørgrav 		free(var_name);
97109958426SBrian Feldman 	}
97209958426SBrian Feldman }
97319261079SEd Maste #endif /* defined(USE_PAM) || defined(HAVE_CYGWIN) */
97409958426SBrian Feldman 
97519261079SEd Maste #ifdef HAVE_CYGWIN
97619261079SEd Maste static void
9774f52dfbbSDag-Erling Smørgrav copy_environment(char **source, char ***env, u_int *envsize)
978a04a10f8SKris Kennaway {
97919261079SEd Maste 	copy_environment_denylist(source, env, envsize, NULL);
9804f52dfbbSDag-Erling Smørgrav }
98119261079SEd Maste #endif
9824f52dfbbSDag-Erling Smørgrav 
9834f52dfbbSDag-Erling Smørgrav static char **
9844f52dfbbSDag-Erling Smørgrav do_setup_env(struct ssh *ssh, Session *s, const char *shell)
9854f52dfbbSDag-Erling Smørgrav {
986a04a10f8SKris Kennaway 	char buf[256];
98747dd1d1bSDag-Erling Smørgrav 	size_t n;
988af12a3e7SDag-Erling Smørgrav 	u_int i, envsize;
989190cef3dSDag-Erling Smørgrav 	char *ocp, *cp, *value, **env, *laddr;
990333ee039SDag-Erling Smørgrav 	struct passwd *pw = s->pw;
9917aee6ffeSDag-Erling Smørgrav #if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN)
992333ee039SDag-Erling Smørgrav 	char *path = NULL;
993333ee039SDag-Erling Smørgrav #else
994c62005fcSDag-Erling Smørgrav 	extern char **environ;
995ca86bcf2SDag-Erling Smørgrav 	char **senv, **var, *val;
996c62005fcSDag-Erling Smørgrav #endif
997a04a10f8SKris Kennaway 
998a04a10f8SKris Kennaway 	/* Initialize the environment. */
999a04a10f8SKris Kennaway 	envsize = 100;
1000333ee039SDag-Erling Smørgrav 	env = xcalloc(envsize, sizeof(char *));
1001a04a10f8SKris Kennaway 	env[0] = NULL;
1002989dd127SDag-Erling Smørgrav 
1003989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN
1004989dd127SDag-Erling Smørgrav 	/*
1005989dd127SDag-Erling Smørgrav 	 * The Windows environment contains some setting which are
1006989dd127SDag-Erling Smørgrav 	 * important for a running system. They must not be dropped.
1007989dd127SDag-Erling Smørgrav 	 */
1008aa49c926SDag-Erling Smørgrav 	{
1009aa49c926SDag-Erling Smørgrav 		char **p;
1010aa49c926SDag-Erling Smørgrav 
1011aa49c926SDag-Erling Smørgrav 		p = fetch_windows_environment();
1012aa49c926SDag-Erling Smørgrav 		copy_environment(p, &env, &envsize);
1013aa49c926SDag-Erling Smørgrav 		free_windows_environment(p);
1014aa49c926SDag-Erling Smørgrav 	}
1015989dd127SDag-Erling Smørgrav #endif
1016a04a10f8SKris Kennaway 
1017c62005fcSDag-Erling Smørgrav 	if (getenv("TZ"))
1018c62005fcSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "TZ", getenv("TZ"));
1019cf2b5f3bSDag-Erling Smørgrav 
1020cf2b5f3bSDag-Erling Smørgrav #ifdef GSSAPI
1021cf2b5f3bSDag-Erling Smørgrav 	/* Allow any GSSAPI methods that we've used to alter
102219261079SEd Maste 	 * the child's environment as they see fit
1023cf2b5f3bSDag-Erling Smørgrav 	 */
1024cf2b5f3bSDag-Erling Smørgrav 	ssh_gssapi_do_child(&env, &envsize);
1025cf2b5f3bSDag-Erling Smørgrav #endif
1026cf2b5f3bSDag-Erling Smørgrav 
1027a04a10f8SKris Kennaway 	/* Set basic environment. */
102821e764dfSDag-Erling Smørgrav 	for (i = 0; i < s->num_env; i++)
1029ca86bcf2SDag-Erling Smørgrav 		child_set_env(&env, &envsize, s->env[i].name, s->env[i].val);
103021e764dfSDag-Erling Smørgrav 
1031a04a10f8SKris Kennaway 	child_set_env(&env, &envsize, "USER", pw->pw_name);
1032a04a10f8SKris Kennaway 	child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
1033e73e9afaSDag-Erling Smørgrav #ifdef _AIX
1034e73e9afaSDag-Erling Smørgrav 	child_set_env(&env, &envsize, "LOGIN", pw->pw_name);
1035e73e9afaSDag-Erling Smørgrav #endif
1036a04a10f8SKris Kennaway 	child_set_env(&env, &envsize, "HOME", pw->pw_dir);
1037ca86bcf2SDag-Erling Smørgrav 	snprintf(buf, sizeof buf, "%.200s/%.50s", _PATH_MAILDIR, pw->pw_name);
1038c62005fcSDag-Erling Smørgrav 	child_set_env(&env, &envsize, "MAIL", buf);
1039989dd127SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1040c62005fcSDag-Erling Smørgrav 	child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
1041c62005fcSDag-Erling Smørgrav 	child_set_env(&env, &envsize, "TERM", "su");
1042ca86bcf2SDag-Erling Smørgrav 	/*
1043ca86bcf2SDag-Erling Smørgrav 	 * Temporarily swap out our real environment with an empty one,
1044ca86bcf2SDag-Erling Smørgrav 	 * let setusercontext() apply any environment variables defined
1045ca86bcf2SDag-Erling Smørgrav 	 * for the user's login class, copy those variables to the child,
1046ca86bcf2SDag-Erling Smørgrav 	 * free the temporary environment, and restore the original.
1047ca86bcf2SDag-Erling Smørgrav 	 */
1048c62005fcSDag-Erling Smørgrav 	senv = environ;
1049ca86bcf2SDag-Erling Smørgrav 	environ = xmalloc(sizeof(*environ));
1050c62005fcSDag-Erling Smørgrav 	*environ = NULL;
1051ca86bcf2SDag-Erling Smørgrav 	(void)setusercontext(lc, pw, pw->pw_uid, LOGIN_SETENV|LOGIN_SETPATH);
1052ca86bcf2SDag-Erling Smørgrav 	for (var = environ; *var != NULL; ++var) {
1053ca86bcf2SDag-Erling Smørgrav 		if ((val = strchr(*var, '=')) != NULL) {
1054ca86bcf2SDag-Erling Smørgrav 			*val++ = '\0';
1055ca86bcf2SDag-Erling Smørgrav 			child_set_env(&env, &envsize, *var, val);
1056ca86bcf2SDag-Erling Smørgrav 		}
1057e4a9863fSDag-Erling Smørgrav 		free(*var);
1058ca86bcf2SDag-Erling Smørgrav 	}
1059e4a9863fSDag-Erling Smørgrav 	free(environ);
1060c62005fcSDag-Erling Smørgrav 	environ = senv;
1061989dd127SDag-Erling Smørgrav #else /* HAVE_LOGIN_CAP */
1062989dd127SDag-Erling Smørgrav # ifndef HAVE_CYGWIN
1063989dd127SDag-Erling Smørgrav 	/*
1064989dd127SDag-Erling Smørgrav 	 * There's no standard path on Windows. The path contains
1065989dd127SDag-Erling Smørgrav 	 * important components pointing to the system directories,
1066989dd127SDag-Erling Smørgrav 	 * needed for loading shared libraries. So the path better
1067989dd127SDag-Erling Smørgrav 	 * remains intact here.
1068989dd127SDag-Erling Smørgrav 	 */
1069cf2b5f3bSDag-Erling Smørgrav #  ifdef HAVE_ETC_DEFAULT_LOGIN
1070cf2b5f3bSDag-Erling Smørgrav 	read_etc_default_login(&env, &envsize, pw->pw_uid);
1071cf2b5f3bSDag-Erling Smørgrav 	path = child_get_env(env, "PATH");
1072cf2b5f3bSDag-Erling Smørgrav #  endif /* HAVE_ETC_DEFAULT_LOGIN */
1073cf2b5f3bSDag-Erling Smørgrav 	if (path == NULL || *path == '\0') {
1074989dd127SDag-Erling Smørgrav 		child_set_env(&env, &envsize, "PATH",
1075ca86bcf2SDag-Erling Smørgrav 		    s->pw->pw_uid == 0 ?  SUPERUSER_PATH : _PATH_STDPATH);
1076cf2b5f3bSDag-Erling Smørgrav 	}
1077989dd127SDag-Erling Smørgrav # endif /* HAVE_CYGWIN */
1078989dd127SDag-Erling Smørgrav #endif /* HAVE_LOGIN_CAP */
1079a04a10f8SKris Kennaway 
108019261079SEd Maste 	if (!options.use_pam) {
108119261079SEd Maste 		snprintf(buf, sizeof buf, "%.200s/%.50s",
108219261079SEd Maste 		    _PATH_MAILDIR, pw->pw_name);
108319261079SEd Maste 		child_set_env(&env, &envsize, "MAIL", buf);
108419261079SEd Maste 	}
108519261079SEd Maste 
1086a04a10f8SKris Kennaway 	/* Normal systems set SHELL by default. */
1087a04a10f8SKris Kennaway 	child_set_env(&env, &envsize, "SHELL", shell);
1088ca86bcf2SDag-Erling Smørgrav 
1089ca3176e7SBrian Feldman 	if (s->term)
1090ca3176e7SBrian Feldman 		child_set_env(&env, &envsize, "TERM", s->term);
1091ca3176e7SBrian Feldman 	if (s->display)
1092ca3176e7SBrian Feldman 		child_set_env(&env, &envsize, "DISPLAY", s->display);
1093989dd127SDag-Erling Smørgrav 
1094aa49c926SDag-Erling Smørgrav 	/*
1095aa49c926SDag-Erling Smørgrav 	 * Since we clear KRB5CCNAME at startup, if it's set now then it
1096aa49c926SDag-Erling Smørgrav 	 * must have been set by a native authentication method (eg AIX or
1097aa49c926SDag-Erling Smørgrav 	 * SIA), so copy it to the child.
1098aa49c926SDag-Erling Smørgrav 	 */
1099aa49c926SDag-Erling Smørgrav 	{
1100aa49c926SDag-Erling Smørgrav 		char *cp;
1101aa49c926SDag-Erling Smørgrav 
1102aa49c926SDag-Erling Smørgrav 		if ((cp = getenv("KRB5CCNAME")) != NULL)
1103aa49c926SDag-Erling Smørgrav 			child_set_env(&env, &envsize, "KRB5CCNAME", cp);
1104aa49c926SDag-Erling Smørgrav 	}
1105aa49c926SDag-Erling Smørgrav 
1106989dd127SDag-Erling Smørgrav #ifdef _AIX
1107989dd127SDag-Erling Smørgrav 	{
1108989dd127SDag-Erling Smørgrav 		char *cp;
1109989dd127SDag-Erling Smørgrav 
1110989dd127SDag-Erling Smørgrav 		if ((cp = getenv("AUTHSTATE")) != NULL)
1111989dd127SDag-Erling Smørgrav 			child_set_env(&env, &envsize, "AUTHSTATE", cp);
1112190cef3dSDag-Erling Smørgrav 		read_environment_file(&env, &envsize, "/etc/environment",
111319261079SEd Maste 		    options.permit_user_env_allowlist);
1114989dd127SDag-Erling Smørgrav 	}
1115989dd127SDag-Erling Smørgrav #endif
1116e8aafc91SKris Kennaway #ifdef KRB5
11175962c0e9SDag-Erling Smørgrav 	if (s->authctxt->krb5_ccname)
1118af12a3e7SDag-Erling Smørgrav 		child_set_env(&env, &envsize, "KRB5CCNAME",
11195962c0e9SDag-Erling Smørgrav 		    s->authctxt->krb5_ccname);
1120af12a3e7SDag-Erling Smørgrav #endif
1121190cef3dSDag-Erling Smørgrav 	if (auth_sock_name != NULL)
1122190cef3dSDag-Erling Smørgrav 		child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
1123190cef3dSDag-Erling Smørgrav 		    auth_sock_name);
1124190cef3dSDag-Erling Smørgrav 
1125190cef3dSDag-Erling Smørgrav 
1126190cef3dSDag-Erling Smørgrav 	/* Set custom environment options from pubkey authentication. */
1127190cef3dSDag-Erling Smørgrav 	if (options.permit_user_env) {
1128190cef3dSDag-Erling Smørgrav 		for (n = 0 ; n < auth_opts->nenv; n++) {
1129190cef3dSDag-Erling Smørgrav 			ocp = xstrdup(auth_opts->env[n]);
1130190cef3dSDag-Erling Smørgrav 			cp = strchr(ocp, '=');
113119261079SEd Maste 			if (cp != NULL) {
1132190cef3dSDag-Erling Smørgrav 				*cp = '\0';
113319261079SEd Maste 				/* Apply PermitUserEnvironment allowlist */
113419261079SEd Maste 				if (options.permit_user_env_allowlist == NULL ||
1135190cef3dSDag-Erling Smørgrav 				    match_pattern_list(ocp,
113619261079SEd Maste 				    options.permit_user_env_allowlist, 0) == 1)
1137190cef3dSDag-Erling Smørgrav 					child_set_env(&env, &envsize,
1138190cef3dSDag-Erling Smørgrav 					    ocp, cp + 1);
1139190cef3dSDag-Erling Smørgrav 			}
1140190cef3dSDag-Erling Smørgrav 			free(ocp);
1141190cef3dSDag-Erling Smørgrav 		}
1142190cef3dSDag-Erling Smørgrav 	}
1143190cef3dSDag-Erling Smørgrav 
1144190cef3dSDag-Erling Smørgrav 	/* read $HOME/.ssh/environment. */
1145190cef3dSDag-Erling Smørgrav 	if (options.permit_user_env) {
114619261079SEd Maste 		snprintf(buf, sizeof buf, "%.200s/%s/environment",
114719261079SEd Maste 		    pw->pw_dir, _PATH_SSH_USER_DIR);
1148190cef3dSDag-Erling Smørgrav 		read_environment_file(&env, &envsize, buf,
114919261079SEd Maste 		    options.permit_user_env_allowlist);
1150190cef3dSDag-Erling Smørgrav 	}
1151190cef3dSDag-Erling Smørgrav 
115209958426SBrian Feldman #ifdef USE_PAM
1153f388f5efSDag-Erling Smørgrav 	/*
1154f388f5efSDag-Erling Smørgrav 	 * Pull in any environment variables that may have
1155f388f5efSDag-Erling Smørgrav 	 * been set by PAM.
1156f388f5efSDag-Erling Smørgrav 	 */
1157ca86bcf2SDag-Erling Smørgrav 	if (options.use_pam) {
11581ec0d754SDag-Erling Smørgrav 		char **p;
1159f388f5efSDag-Erling Smørgrav 
11604f52dfbbSDag-Erling Smørgrav 		/*
116119261079SEd Maste 		 * Don't allow PAM-internal env vars to leak
116219261079SEd Maste 		 * back into the session environment.
11634f52dfbbSDag-Erling Smørgrav 		 */
116419261079SEd Maste #define PAM_ENV_DENYLIST  "SSH_AUTH_INFO*,SSH_CONNECTION*"
11651ec0d754SDag-Erling Smørgrav 		p = fetch_pam_child_environment();
116619261079SEd Maste 		copy_environment_denylist(p, &env, &envsize,
116719261079SEd Maste 		    PAM_ENV_DENYLIST);
11681ec0d754SDag-Erling Smørgrav 		free_pam_environment(p);
11691ec0d754SDag-Erling Smørgrav 
11701ec0d754SDag-Erling Smørgrav 		p = fetch_pam_environment();
117119261079SEd Maste 		copy_environment_denylist(p, &env, &envsize,
117219261079SEd Maste 		    PAM_ENV_DENYLIST);
1173f388f5efSDag-Erling Smørgrav 		free_pam_environment(p);
1174f388f5efSDag-Erling Smørgrav 	}
117509958426SBrian Feldman #endif /* USE_PAM */
117609958426SBrian Feldman 
1177190cef3dSDag-Erling Smørgrav 	/* Environment specified by admin */
1178190cef3dSDag-Erling Smørgrav 	for (i = 0; i < options.num_setenv; i++) {
1179190cef3dSDag-Erling Smørgrav 		cp = xstrdup(options.setenv[i]);
1180190cef3dSDag-Erling Smørgrav 		if ((value = strchr(cp, '=')) == NULL) {
1181190cef3dSDag-Erling Smørgrav 			/* shouldn't happen; vars are checked in servconf.c */
1182190cef3dSDag-Erling Smørgrav 			fatal("Invalid config SetEnv: %s", options.setenv[i]);
1183a04a10f8SKris Kennaway 		}
1184190cef3dSDag-Erling Smørgrav 		*value++ = '\0';
1185190cef3dSDag-Erling Smørgrav 		child_set_env(&env, &envsize, cp, value);
1186190cef3dSDag-Erling Smørgrav 	}
1187190cef3dSDag-Erling Smørgrav 
1188190cef3dSDag-Erling Smørgrav 	/* SSH_CLIENT deprecated */
1189190cef3dSDag-Erling Smørgrav 	snprintf(buf, sizeof buf, "%.50s %d %d",
1190190cef3dSDag-Erling Smørgrav 	    ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
1191190cef3dSDag-Erling Smørgrav 	    ssh_local_port(ssh));
1192190cef3dSDag-Erling Smørgrav 	child_set_env(&env, &envsize, "SSH_CLIENT", buf);
1193190cef3dSDag-Erling Smørgrav 
119419261079SEd Maste 	laddr = get_local_ipaddr(ssh_packet_get_connection_in(ssh));
1195190cef3dSDag-Erling Smørgrav 	snprintf(buf, sizeof buf, "%.50s %d %.50s %d",
1196190cef3dSDag-Erling Smørgrav 	    ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
1197190cef3dSDag-Erling Smørgrav 	    laddr, ssh_local_port(ssh));
1198190cef3dSDag-Erling Smørgrav 	free(laddr);
1199190cef3dSDag-Erling Smørgrav 	child_set_env(&env, &envsize, "SSH_CONNECTION", buf);
1200190cef3dSDag-Erling Smørgrav 
1201190cef3dSDag-Erling Smørgrav 	if (tun_fwd_ifnames != NULL)
1202190cef3dSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "SSH_TUNNEL", tun_fwd_ifnames);
1203190cef3dSDag-Erling Smørgrav 	if (auth_info_file != NULL)
1204190cef3dSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "SSH_USER_AUTH", auth_info_file);
1205190cef3dSDag-Erling Smørgrav 	if (s->ttyfd != -1)
1206190cef3dSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "SSH_TTY", s->tty);
1207190cef3dSDag-Erling Smørgrav 	if (original_command)
1208190cef3dSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND",
1209190cef3dSDag-Erling Smørgrav 		    original_command);
1210190cef3dSDag-Erling Smørgrav 
1211a04a10f8SKris Kennaway 	if (debug_flag) {
1212a04a10f8SKris Kennaway 		/* dump the environment */
1213a04a10f8SKris Kennaway 		fprintf(stderr, "Environment:\n");
1214a04a10f8SKris Kennaway 		for (i = 0; env[i]; i++)
1215a04a10f8SKris Kennaway 			fprintf(stderr, "  %.200s\n", env[i]);
1216a04a10f8SKris Kennaway 	}
1217af12a3e7SDag-Erling Smørgrav 	return env;
1218e8aafc91SKris Kennaway }
1219ca3176e7SBrian Feldman 
1220ca3176e7SBrian Feldman /*
1221af12a3e7SDag-Erling Smørgrav  * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found
1222af12a3e7SDag-Erling Smørgrav  * first in this order).
1223ca3176e7SBrian Feldman  */
1224af12a3e7SDag-Erling Smørgrav static void
122547dd1d1bSDag-Erling Smørgrav do_rc_files(struct ssh *ssh, Session *s, const char *shell)
1226af12a3e7SDag-Erling Smørgrav {
1227af12a3e7SDag-Erling Smørgrav 	FILE *f = NULL;
122819261079SEd Maste 	char *cmd = NULL, *user_rc = NULL;
1229af12a3e7SDag-Erling Smørgrav 	int do_xauth;
1230af12a3e7SDag-Erling Smørgrav 	struct stat st;
1231a04a10f8SKris Kennaway 
1232af12a3e7SDag-Erling Smørgrav 	do_xauth =
1233af12a3e7SDag-Erling Smørgrav 	    s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL;
123419261079SEd Maste 	xasprintf(&user_rc, "%s/%s", s->pw->pw_dir, _PATH_SSH_USER_RC);
1235a04a10f8SKris Kennaway 
1236d4af9e69SDag-Erling Smørgrav 	/* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */
1237d4af9e69SDag-Erling Smørgrav 	if (!s->is_subsystem && options.adm_forced_command == NULL &&
123847dd1d1bSDag-Erling Smørgrav 	    auth_opts->permit_user_rc && options.permit_user_rc &&
123919261079SEd Maste 	    stat(user_rc, &st) >= 0) {
124019261079SEd Maste 		if (xasprintf(&cmd, "%s -c '%s %s'", shell, _PATH_BSHELL,
124119261079SEd Maste 		    user_rc) == -1)
124219261079SEd Maste 			fatal_f("xasprintf: %s", strerror(errno));
1243a04a10f8SKris Kennaway 		if (debug_flag)
1244e9fd63dfSBrian Feldman 			fprintf(stderr, "Running %s\n", cmd);
1245e9fd63dfSBrian Feldman 		f = popen(cmd, "w");
1246a04a10f8SKris Kennaway 		if (f) {
1247ca3176e7SBrian Feldman 			if (do_xauth)
1248ca3176e7SBrian Feldman 				fprintf(f, "%s %s\n", s->auth_proto,
1249ca3176e7SBrian Feldman 				    s->auth_data);
1250a04a10f8SKris Kennaway 			pclose(f);
1251a04a10f8SKris Kennaway 		} else
1252ca3176e7SBrian Feldman 			fprintf(stderr, "Could not run %s\n",
125319261079SEd Maste 			    user_rc);
1254ca3176e7SBrian Feldman 	} else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) {
1255a04a10f8SKris Kennaway 		if (debug_flag)
1256ca3176e7SBrian Feldman 			fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,
1257ca3176e7SBrian Feldman 			    _PATH_SSH_SYSTEM_RC);
1258ca3176e7SBrian Feldman 		f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w");
1259a04a10f8SKris Kennaway 		if (f) {
1260ca3176e7SBrian Feldman 			if (do_xauth)
1261ca3176e7SBrian Feldman 				fprintf(f, "%s %s\n", s->auth_proto,
1262ca3176e7SBrian Feldman 				    s->auth_data);
1263a04a10f8SKris Kennaway 			pclose(f);
1264a04a10f8SKris Kennaway 		} else
1265ca3176e7SBrian Feldman 			fprintf(stderr, "Could not run %s\n",
1266ca3176e7SBrian Feldman 			    _PATH_SSH_SYSTEM_RC);
1267ca3176e7SBrian Feldman 	} else if (do_xauth && options.xauth_location != NULL) {
1268a04a10f8SKris Kennaway 		/* Add authority data to .Xauthority if appropriate. */
1269db1cb46cSKris Kennaway 		if (debug_flag) {
1270db1cb46cSKris Kennaway 			fprintf(stderr,
1271e73e9afaSDag-Erling Smørgrav 			    "Running %.500s remove %.100s\n",
1272e73e9afaSDag-Erling Smørgrav 			    options.xauth_location, s->auth_display);
1273e73e9afaSDag-Erling Smørgrav 			fprintf(stderr,
1274e73e9afaSDag-Erling Smørgrav 			    "%.500s add %.100s %.100s %.100s\n",
1275af12a3e7SDag-Erling Smørgrav 			    options.xauth_location, s->auth_display,
1276ca3176e7SBrian Feldman 			    s->auth_proto, s->auth_data);
1277db1cb46cSKris Kennaway 		}
127819261079SEd Maste 		if (xasprintf(&cmd, "%s -q -", options.xauth_location) == -1)
127919261079SEd Maste 			fatal_f("xasprintf: %s", strerror(errno));
1280c2d3a559SKris Kennaway 		f = popen(cmd, "w");
1281a04a10f8SKris Kennaway 		if (f) {
1282e73e9afaSDag-Erling Smørgrav 			fprintf(f, "remove %s\n",
1283e73e9afaSDag-Erling Smørgrav 			    s->auth_display);
1284af12a3e7SDag-Erling Smørgrav 			fprintf(f, "add %s %s %s\n",
1285af12a3e7SDag-Erling Smørgrav 			    s->auth_display, s->auth_proto,
1286ca3176e7SBrian Feldman 			    s->auth_data);
1287a04a10f8SKris Kennaway 			pclose(f);
1288c2d3a559SKris Kennaway 		} else {
1289c2d3a559SKris Kennaway 			fprintf(stderr, "Could not run %s\n",
1290c2d3a559SKris Kennaway 			    cmd);
1291a04a10f8SKris Kennaway 		}
1292a04a10f8SKris Kennaway 	}
129319261079SEd Maste 	free(cmd);
129419261079SEd Maste 	free(user_rc);
1295a04a10f8SKris Kennaway }
1296ca3176e7SBrian Feldman 
1297af12a3e7SDag-Erling Smørgrav static void
1298af12a3e7SDag-Erling Smørgrav do_nologin(struct passwd *pw)
1299af12a3e7SDag-Erling Smørgrav {
1300af12a3e7SDag-Erling Smørgrav 	FILE *f = NULL;
1301d93a896eSDag-Erling Smørgrav 	const char *nl;
1302d93a896eSDag-Erling Smørgrav 	char buf[1024], *def_nl = _PATH_NOLOGIN;
1303b15c8340SDag-Erling Smørgrav 	struct stat sb;
1304af12a3e7SDag-Erling Smørgrav 
1305af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1306462c32cbSDag-Erling Smørgrav 	if (login_getcapbool(lc, "ignorenologin", 0) || pw->pw_uid == 0)
1307b15c8340SDag-Erling Smørgrav 		return;
1308b15c8340SDag-Erling Smørgrav 	nl = login_getcapstr(lc, "nologin", def_nl, def_nl);
1309af12a3e7SDag-Erling Smørgrav #else
1310b15c8340SDag-Erling Smørgrav 	if (pw->pw_uid == 0)
1311b15c8340SDag-Erling Smørgrav 		return;
1312b15c8340SDag-Erling Smørgrav 	nl = def_nl;
1313af12a3e7SDag-Erling Smørgrav #endif
1314d93a896eSDag-Erling Smørgrav 	if (stat(nl, &sb) == -1)
1315b15c8340SDag-Erling Smørgrav 		return;
1316b15c8340SDag-Erling Smørgrav 
1317b15c8340SDag-Erling Smørgrav 	/* /etc/nologin exists.  Print its contents if we can and exit. */
1318b15c8340SDag-Erling Smørgrav 	logit("User %.100s not allowed because %s exists", pw->pw_name, nl);
1319b15c8340SDag-Erling Smørgrav 	if ((f = fopen(nl, "r")) != NULL) {
1320af12a3e7SDag-Erling Smørgrav 		while (fgets(buf, sizeof(buf), f))
1321af12a3e7SDag-Erling Smørgrav 			fputs(buf, stderr);
1322af12a3e7SDag-Erling Smørgrav 		fclose(f);
1323af12a3e7SDag-Erling Smørgrav 	}
1324b15c8340SDag-Erling Smørgrav 	exit(254);
1325af12a3e7SDag-Erling Smørgrav }
1326af12a3e7SDag-Erling Smørgrav 
1327d4af9e69SDag-Erling Smørgrav /*
1328d4af9e69SDag-Erling Smørgrav  * Chroot into a directory after checking it for safety: all path components
1329d4af9e69SDag-Erling Smørgrav  * must be root-owned directories with strict permissions.
1330d4af9e69SDag-Erling Smørgrav  */
1331d4af9e69SDag-Erling Smørgrav static void
1332d4af9e69SDag-Erling Smørgrav safely_chroot(const char *path, uid_t uid)
1333d4af9e69SDag-Erling Smørgrav {
1334d4af9e69SDag-Erling Smørgrav 	const char *cp;
1335bc5531deSDag-Erling Smørgrav 	char component[PATH_MAX];
1336d4af9e69SDag-Erling Smørgrav 	struct stat st;
1337d4af9e69SDag-Erling Smørgrav 
133819261079SEd Maste 	if (!path_absolute(path))
1339d4af9e69SDag-Erling Smørgrav 		fatal("chroot path does not begin at root");
1340d4af9e69SDag-Erling Smørgrav 	if (strlen(path) >= sizeof(component))
1341d4af9e69SDag-Erling Smørgrav 		fatal("chroot path too long");
1342d4af9e69SDag-Erling Smørgrav 
1343d4af9e69SDag-Erling Smørgrav 	/*
1344d4af9e69SDag-Erling Smørgrav 	 * Descend the path, checking that each component is a
1345d4af9e69SDag-Erling Smørgrav 	 * root-owned directory with strict permissions.
1346d4af9e69SDag-Erling Smørgrav 	 */
1347d4af9e69SDag-Erling Smørgrav 	for (cp = path; cp != NULL;) {
1348d4af9e69SDag-Erling Smørgrav 		if ((cp = strchr(cp, '/')) == NULL)
1349d4af9e69SDag-Erling Smørgrav 			strlcpy(component, path, sizeof(component));
1350d4af9e69SDag-Erling Smørgrav 		else {
1351d4af9e69SDag-Erling Smørgrav 			cp++;
1352d4af9e69SDag-Erling Smørgrav 			memcpy(component, path, cp - path);
1353d4af9e69SDag-Erling Smørgrav 			component[cp - path] = '\0';
1354d4af9e69SDag-Erling Smørgrav 		}
1355d4af9e69SDag-Erling Smørgrav 
135619261079SEd Maste 		debug3_f("checking '%s'", component);
1357d4af9e69SDag-Erling Smørgrav 
1358d4af9e69SDag-Erling Smørgrav 		if (stat(component, &st) != 0)
135919261079SEd Maste 			fatal_f("stat(\"%s\"): %s",
1360d4af9e69SDag-Erling Smørgrav 			    component, strerror(errno));
1361d4af9e69SDag-Erling Smørgrav 		if (st.st_uid != 0 || (st.st_mode & 022) != 0)
1362d4af9e69SDag-Erling Smørgrav 			fatal("bad ownership or modes for chroot "
1363d4af9e69SDag-Erling Smørgrav 			    "directory %s\"%s\"",
1364d4af9e69SDag-Erling Smørgrav 			    cp == NULL ? "" : "component ", component);
1365d4af9e69SDag-Erling Smørgrav 		if (!S_ISDIR(st.st_mode))
1366d4af9e69SDag-Erling Smørgrav 			fatal("chroot path %s\"%s\" is not a directory",
1367d4af9e69SDag-Erling Smørgrav 			    cp == NULL ? "" : "component ", component);
1368d4af9e69SDag-Erling Smørgrav 
1369d4af9e69SDag-Erling Smørgrav 	}
1370d4af9e69SDag-Erling Smørgrav 
1371d4af9e69SDag-Erling Smørgrav 	if (chdir(path) == -1)
1372d4af9e69SDag-Erling Smørgrav 		fatal("Unable to chdir to chroot path \"%s\": "
1373d4af9e69SDag-Erling Smørgrav 		    "%s", path, strerror(errno));
1374d4af9e69SDag-Erling Smørgrav 	if (chroot(path) == -1)
1375d4af9e69SDag-Erling Smørgrav 		fatal("chroot(\"%s\"): %s", path, strerror(errno));
1376d4af9e69SDag-Erling Smørgrav 	if (chdir("/") == -1)
137719261079SEd Maste 		fatal_f("chdir(/) after chroot: %s", strerror(errno));
1378d4af9e69SDag-Erling Smørgrav 	verbose("Changed root directory to \"%s\"", path);
1379d4af9e69SDag-Erling Smørgrav }
1380d4af9e69SDag-Erling Smørgrav 
1381af12a3e7SDag-Erling Smørgrav /* Set login name, uid, gid, and groups. */
1382989dd127SDag-Erling Smørgrav void
138380628bacSDag-Erling Smørgrav do_setusercontext(struct passwd *pw)
1384af12a3e7SDag-Erling Smørgrav {
1385190cef3dSDag-Erling Smørgrav 	char uidstr[32], *chroot_path, *tmp;
1386d4af9e69SDag-Erling Smørgrav 
13874a421b63SDag-Erling Smørgrav 	platform_setusercontext(pw);
1388d4af9e69SDag-Erling Smørgrav 
13894a421b63SDag-Erling Smørgrav 	if (platform_privileged_uidswap()) {
1390989dd127SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1391989dd127SDag-Erling Smørgrav 		if (setusercontext(lc, pw, pw->pw_uid,
1392d4af9e69SDag-Erling Smørgrav 		    (LOGIN_SETALL & ~(LOGIN_SETENV|LOGIN_SETPATH|LOGIN_SETUSER))) < 0) {
1393989dd127SDag-Erling Smørgrav 			perror("unable to set user context");
1394989dd127SDag-Erling Smørgrav 			exit(1);
1395989dd127SDag-Erling Smørgrav 		}
1396989dd127SDag-Erling Smørgrav #else
1397af12a3e7SDag-Erling Smørgrav 		if (setlogin(pw->pw_name) < 0)
1398af12a3e7SDag-Erling Smørgrav 			error("setlogin failed: %s", strerror(errno));
1399af12a3e7SDag-Erling Smørgrav 		if (setgid(pw->pw_gid) < 0) {
1400af12a3e7SDag-Erling Smørgrav 			perror("setgid");
1401af12a3e7SDag-Erling Smørgrav 			exit(1);
1402af12a3e7SDag-Erling Smørgrav 		}
1403af12a3e7SDag-Erling Smørgrav 		/* Initialize the group list. */
1404af12a3e7SDag-Erling Smørgrav 		if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
1405af12a3e7SDag-Erling Smørgrav 			perror("initgroups");
1406af12a3e7SDag-Erling Smørgrav 			exit(1);
1407af12a3e7SDag-Erling Smørgrav 		}
1408af12a3e7SDag-Erling Smørgrav 		endgrent();
1409d4af9e69SDag-Erling Smørgrav #endif
1410b15c8340SDag-Erling Smørgrav 
14114a421b63SDag-Erling Smørgrav 		platform_setusercontext_post_groups(pw);
14128ad9b54aSDag-Erling Smørgrav 
1413acc1a9efSDag-Erling Smørgrav 		if (!in_chroot && options.chroot_directory != NULL &&
1414d4af9e69SDag-Erling Smørgrav 		    strcasecmp(options.chroot_directory, "none") != 0) {
1415d4af9e69SDag-Erling Smørgrav 			tmp = tilde_expand_filename(options.chroot_directory,
1416d4af9e69SDag-Erling Smørgrav 			    pw->pw_uid);
1417190cef3dSDag-Erling Smørgrav 			snprintf(uidstr, sizeof(uidstr), "%llu",
1418190cef3dSDag-Erling Smørgrav 			    (unsigned long long)pw->pw_uid);
1419d4af9e69SDag-Erling Smørgrav 			chroot_path = percent_expand(tmp, "h", pw->pw_dir,
1420190cef3dSDag-Erling Smørgrav 			    "u", pw->pw_name, "U", uidstr, (char *)NULL);
1421d4af9e69SDag-Erling Smørgrav 			safely_chroot(chroot_path, pw->pw_uid);
1422d4af9e69SDag-Erling Smørgrav 			free(tmp);
1423d4af9e69SDag-Erling Smørgrav 			free(chroot_path);
1424e4a9863fSDag-Erling Smørgrav 			/* Make sure we don't attempt to chroot again */
1425e4a9863fSDag-Erling Smørgrav 			free(options.chroot_directory);
1426e4a9863fSDag-Erling Smørgrav 			options.chroot_directory = NULL;
1427acc1a9efSDag-Erling Smørgrav 			in_chroot = 1;
1428d4af9e69SDag-Erling Smørgrav 		}
1429d4af9e69SDag-Erling Smørgrav 
1430d4af9e69SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1431d4af9e69SDag-Erling Smørgrav 		if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUSER) < 0) {
1432d4af9e69SDag-Erling Smørgrav 			perror("unable to set user context (setuser)");
1433d4af9e69SDag-Erling Smørgrav 			exit(1);
1434d4af9e69SDag-Erling Smørgrav 		}
14352ec88e9dSDag-Erling Smørgrav 		/*
14362ec88e9dSDag-Erling Smørgrav 		 * FreeBSD's setusercontext() will not apply the user's
14372ec88e9dSDag-Erling Smørgrav 		 * own umask setting unless running with the user's UID.
14382ec88e9dSDag-Erling Smørgrav 		 */
14396888a9beSDag-Erling Smørgrav 		(void) setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUMASK);
1440d4af9e69SDag-Erling Smørgrav #else
1441f7167e0eSDag-Erling Smørgrav # ifdef USE_LIBIAF
1442acc1a9efSDag-Erling Smørgrav 		/*
1443acc1a9efSDag-Erling Smørgrav 		 * In a chroot environment, the set_id() will always fail;
1444acc1a9efSDag-Erling Smørgrav 		 * typically because of the lack of necessary authentication
1445acc1a9efSDag-Erling Smørgrav 		 * services and runtime such as ./usr/lib/libiaf.so,
1446acc1a9efSDag-Erling Smørgrav 		 * ./usr/lib/libpam.so.1, and ./etc/passwd We skip it in the
1447acc1a9efSDag-Erling Smørgrav 		 * internal sftp chroot case.  We'll lose auditing and ACLs but
1448acc1a9efSDag-Erling Smørgrav 		 * permanently_set_uid will take care of the rest.
1449a0ee8cc6SDag-Erling Smørgrav 		 */
1450acc1a9efSDag-Erling Smørgrav 		if (!in_chroot && set_id(pw->pw_name) != 0)
1451f7167e0eSDag-Erling Smørgrav 			fatal("set_id(%s) Failed", pw->pw_name);
1452f7167e0eSDag-Erling Smørgrav # endif /* USE_LIBIAF */
1453af12a3e7SDag-Erling Smørgrav 		/* Permanently switch to the desired uid. */
1454af12a3e7SDag-Erling Smørgrav 		permanently_set_uid(pw);
1455989dd127SDag-Erling Smørgrav #endif
1456e4a9863fSDag-Erling Smørgrav 	} else if (options.chroot_directory != NULL &&
1457e4a9863fSDag-Erling Smørgrav 	    strcasecmp(options.chroot_directory, "none") != 0) {
1458e4a9863fSDag-Erling Smørgrav 		fatal("server lacks privileges to chroot to ChrootDirectory");
1459af12a3e7SDag-Erling Smørgrav 	}
1460e73e9afaSDag-Erling Smørgrav 
1461af12a3e7SDag-Erling Smørgrav 	if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
1462af12a3e7SDag-Erling Smørgrav 		fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
146380628bacSDag-Erling Smørgrav }
146480628bacSDag-Erling Smørgrav 
146580628bacSDag-Erling Smørgrav static void
14661ec0d754SDag-Erling Smørgrav do_pwchange(Session *s)
14671ec0d754SDag-Erling Smørgrav {
146821e764dfSDag-Erling Smørgrav 	fflush(NULL);
14691ec0d754SDag-Erling Smørgrav 	fprintf(stderr, "WARNING: Your password has expired.\n");
14701ec0d754SDag-Erling Smørgrav 	if (s->ttyfd != -1) {
14711ec0d754SDag-Erling Smørgrav 		fprintf(stderr,
14721ec0d754SDag-Erling Smørgrav 		    "You must change your password now and login again!\n");
1473e146993eSDag-Erling Smørgrav #ifdef WITH_SELINUX
1474e146993eSDag-Erling Smørgrav 		setexeccon(NULL);
1475e146993eSDag-Erling Smørgrav #endif
1476aa49c926SDag-Erling Smørgrav #ifdef PASSWD_NEEDS_USERNAME
1477aa49c926SDag-Erling Smørgrav 		execl(_PATH_PASSWD_PROG, "passwd", s->pw->pw_name,
1478aa49c926SDag-Erling Smørgrav 		    (char *)NULL);
1479aa49c926SDag-Erling Smørgrav #else
14801ec0d754SDag-Erling Smørgrav 		execl(_PATH_PASSWD_PROG, "passwd", (char *)NULL);
1481aa49c926SDag-Erling Smørgrav #endif
14821ec0d754SDag-Erling Smørgrav 		perror("passwd");
14831ec0d754SDag-Erling Smørgrav 	} else {
14841ec0d754SDag-Erling Smørgrav 		fprintf(stderr,
14851ec0d754SDag-Erling Smørgrav 		    "Password change required but no TTY available.\n");
14861ec0d754SDag-Erling Smørgrav 	}
14871ec0d754SDag-Erling Smørgrav 	exit(1);
14881ec0d754SDag-Erling Smørgrav }
14891ec0d754SDag-Erling Smørgrav 
14901ec0d754SDag-Erling Smørgrav static void
14914f52dfbbSDag-Erling Smørgrav child_close_fds(struct ssh *ssh)
14921ec0d754SDag-Erling Smørgrav {
1493bc5531deSDag-Erling Smørgrav 	extern int auth_sock;
1494e4a9863fSDag-Erling Smørgrav 
1495bc5531deSDag-Erling Smørgrav 	if (auth_sock != -1) {
1496bc5531deSDag-Erling Smørgrav 		close(auth_sock);
1497bc5531deSDag-Erling Smørgrav 		auth_sock = -1;
1498e4a9863fSDag-Erling Smørgrav 	}
1499e4a9863fSDag-Erling Smørgrav 
150019261079SEd Maste 	if (ssh_packet_get_connection_in(ssh) ==
150119261079SEd Maste 	    ssh_packet_get_connection_out(ssh))
150219261079SEd Maste 		close(ssh_packet_get_connection_in(ssh));
15031ec0d754SDag-Erling Smørgrav 	else {
150419261079SEd Maste 		close(ssh_packet_get_connection_in(ssh));
150519261079SEd Maste 		close(ssh_packet_get_connection_out(ssh));
15061ec0d754SDag-Erling Smørgrav 	}
15071ec0d754SDag-Erling Smørgrav 	/*
15081ec0d754SDag-Erling Smørgrav 	 * Close all descriptors related to channels.  They will still remain
15091ec0d754SDag-Erling Smørgrav 	 * open in the parent.
15101ec0d754SDag-Erling Smørgrav 	 */
15111ec0d754SDag-Erling Smørgrav 	/* XXX better use close-on-exec? -markus */
15124f52dfbbSDag-Erling Smørgrav 	channel_close_all(ssh);
15131ec0d754SDag-Erling Smørgrav 
15141ec0d754SDag-Erling Smørgrav 	/*
15151ec0d754SDag-Erling Smørgrav 	 * Close any extra file descriptors.  Note that there may still be
15161ec0d754SDag-Erling Smørgrav 	 * descriptors left by system functions.  They will be closed later.
15171ec0d754SDag-Erling Smørgrav 	 */
15181ec0d754SDag-Erling Smørgrav 	endpwent();
15191ec0d754SDag-Erling Smørgrav 
152019261079SEd Maste 	/* Stop directing logs to a high-numbered fd before we close it */
152119261079SEd Maste 	log_redirect_stderr_to(NULL);
152219261079SEd Maste 
15231ec0d754SDag-Erling Smørgrav 	/*
1524b74df5b2SDag-Erling Smørgrav 	 * Close any extra open file descriptors so that we don't have them
15251ec0d754SDag-Erling Smørgrav 	 * hanging around in clients.  Note that we want to do this after
15261ec0d754SDag-Erling Smørgrav 	 * initgroups, because at least on Solaris 2.3 it leaves file
15271ec0d754SDag-Erling Smørgrav 	 * descriptors open.
15281ec0d754SDag-Erling Smørgrav 	 */
15294a421b63SDag-Erling Smørgrav 	closefrom(STDERR_FILENO + 1);
15301ec0d754SDag-Erling Smørgrav }
15311ec0d754SDag-Erling Smørgrav 
1532af12a3e7SDag-Erling Smørgrav /*
1533af12a3e7SDag-Erling Smørgrav  * Performs common processing for the child, such as setting up the
1534af12a3e7SDag-Erling Smørgrav  * environment, closing extra file descriptors, setting the user and group
1535af12a3e7SDag-Erling Smørgrav  * ids, and executing the command or shell.
1536af12a3e7SDag-Erling Smørgrav  */
1537d4af9e69SDag-Erling Smørgrav #define ARGV_MAX 10
1538af12a3e7SDag-Erling Smørgrav void
15394f52dfbbSDag-Erling Smørgrav do_child(struct ssh *ssh, Session *s, const char *command)
1540af12a3e7SDag-Erling Smørgrav {
1541af12a3e7SDag-Erling Smørgrav 	extern char **environ;
154219261079SEd Maste 	char **env, *argv[ARGV_MAX], remote_id[512];
1543ca86bcf2SDag-Erling Smørgrav 	const char *shell, *shell0;
1544af12a3e7SDag-Erling Smørgrav 	struct passwd *pw = s->pw;
1545d4af9e69SDag-Erling Smørgrav 	int r = 0;
1546af12a3e7SDag-Erling Smørgrav 
154719261079SEd Maste 	sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id));
154819261079SEd Maste 
1549af12a3e7SDag-Erling Smørgrav 	/* remove hostkey from the child's memory */
1550af12a3e7SDag-Erling Smørgrav 	destroy_sensitive_data();
155119261079SEd Maste 	ssh_packet_clear_keys(ssh);
1552af12a3e7SDag-Erling Smørgrav 
15531ec0d754SDag-Erling Smørgrav 	/* Force a password change */
15541ec0d754SDag-Erling Smørgrav 	if (s->authctxt->force_pwchange) {
15551ec0d754SDag-Erling Smørgrav 		do_setusercontext(pw);
15564f52dfbbSDag-Erling Smørgrav 		child_close_fds(ssh);
15571ec0d754SDag-Erling Smørgrav 		do_pwchange(s);
15581ec0d754SDag-Erling Smørgrav 		exit(1);
15591ec0d754SDag-Erling Smørgrav 	}
15601ec0d754SDag-Erling Smørgrav 
1561af12a3e7SDag-Erling Smørgrav 	/*
1562af12a3e7SDag-Erling Smørgrav 	 * Login(1) does this as well, and it needs uid 0 for the "-h"
1563af12a3e7SDag-Erling Smørgrav 	 * switch, so we let login(1) to this for us.
1564af12a3e7SDag-Erling Smørgrav 	 */
1565989dd127SDag-Erling Smørgrav #ifdef HAVE_OSF_SIA
1566e73e9afaSDag-Erling Smørgrav 	session_setup_sia(pw, s->ttyfd == -1 ? NULL : s->tty);
1567989dd127SDag-Erling Smørgrav 	if (!check_quietlogin(s, command))
1568989dd127SDag-Erling Smørgrav 		do_motd();
1569989dd127SDag-Erling Smørgrav #else /* HAVE_OSF_SIA */
1570b74df5b2SDag-Erling Smørgrav 	/* When PAM is enabled we rely on it to do the nologin check */
1571b74df5b2SDag-Erling Smørgrav 	if (!options.use_pam)
1572af12a3e7SDag-Erling Smørgrav 		do_nologin(pw);
1573989dd127SDag-Erling Smørgrav 	do_setusercontext(pw);
157421e764dfSDag-Erling Smørgrav 	/*
157521e764dfSDag-Erling Smørgrav 	 * PAM session modules in do_setusercontext may have
157621e764dfSDag-Erling Smørgrav 	 * generated messages, so if this in an interactive
157721e764dfSDag-Erling Smørgrav 	 * login then display them too.
157821e764dfSDag-Erling Smørgrav 	 */
1579aa49c926SDag-Erling Smørgrav 	if (!check_quietlogin(s, command))
158021e764dfSDag-Erling Smørgrav 		display_loginmsg();
1581989dd127SDag-Erling Smørgrav #endif /* HAVE_OSF_SIA */
1582af12a3e7SDag-Erling Smørgrav 
1583aa49c926SDag-Erling Smørgrav #ifdef USE_PAM
1584ca86bcf2SDag-Erling Smørgrav 	if (options.use_pam && !is_pam_session_open()) {
1585aa49c926SDag-Erling Smørgrav 		debug3("PAM session not opened, exiting");
1586aa49c926SDag-Erling Smørgrav 		display_loginmsg();
1587aa49c926SDag-Erling Smørgrav 		exit(254);
1588aa49c926SDag-Erling Smørgrav 	}
1589aa49c926SDag-Erling Smørgrav #endif
1590aa49c926SDag-Erling Smørgrav 
1591af12a3e7SDag-Erling Smørgrav 	/*
1592af12a3e7SDag-Erling Smørgrav 	 * Get the shell from the password data.  An empty shell field is
1593af12a3e7SDag-Erling Smørgrav 	 * legal, and means /bin/sh.
1594af12a3e7SDag-Erling Smørgrav 	 */
1595af12a3e7SDag-Erling Smørgrav 	shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
1596e73e9afaSDag-Erling Smørgrav 
1597e73e9afaSDag-Erling Smørgrav 	/*
1598e73e9afaSDag-Erling Smørgrav 	 * Make sure $SHELL points to the shell from the password file,
1599e73e9afaSDag-Erling Smørgrav 	 * even if shell is overridden from login.conf
1600e73e9afaSDag-Erling Smørgrav 	 */
16014f52dfbbSDag-Erling Smørgrav 	env = do_setup_env(ssh, s, shell);
1602e73e9afaSDag-Erling Smørgrav 
1603af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1604af12a3e7SDag-Erling Smørgrav 	shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);
1605af12a3e7SDag-Erling Smørgrav #endif
1606af12a3e7SDag-Erling Smørgrav 
1607af12a3e7SDag-Erling Smørgrav 	/*
1608af12a3e7SDag-Erling Smørgrav 	 * Close the connection descriptors; note that this is the child, and
1609af12a3e7SDag-Erling Smørgrav 	 * the server will still have the socket open, and it is important
1610af12a3e7SDag-Erling Smørgrav 	 * that we do not shutdown it.  Note that the descriptors cannot be
1611af12a3e7SDag-Erling Smørgrav 	 * closed before building the environment, as we call
1612076ad2f8SDag-Erling Smørgrav 	 * ssh_remote_ipaddr there.
1613af12a3e7SDag-Erling Smørgrav 	 */
16144f52dfbbSDag-Erling Smørgrav 	child_close_fds(ssh);
1615af12a3e7SDag-Erling Smørgrav 
1616af12a3e7SDag-Erling Smørgrav 	/*
1617af12a3e7SDag-Erling Smørgrav 	 * Must take new environment into use so that .ssh/rc,
1618af12a3e7SDag-Erling Smørgrav 	 * /etc/ssh/sshrc and xauth are run in the proper environment.
1619af12a3e7SDag-Erling Smørgrav 	 */
1620af12a3e7SDag-Erling Smørgrav 	environ = env;
1621af12a3e7SDag-Erling Smørgrav 
16221ec0d754SDag-Erling Smørgrav #if defined(KRB5) && defined(USE_AFS)
16231ec0d754SDag-Erling Smørgrav 	/*
16241ec0d754SDag-Erling Smørgrav 	 * At this point, we check to see if AFS is active and if we have
16251ec0d754SDag-Erling Smørgrav 	 * a valid Kerberos 5 TGT. If so, it seems like a good idea to see
16261ec0d754SDag-Erling Smørgrav 	 * if we can (and need to) extend the ticket into an AFS token. If
16271ec0d754SDag-Erling Smørgrav 	 * we don't do this, we run into potential problems if the user's
16281ec0d754SDag-Erling Smørgrav 	 * home directory is in AFS and it's not world-readable.
16291ec0d754SDag-Erling Smørgrav 	 */
16301ec0d754SDag-Erling Smørgrav 
16311ec0d754SDag-Erling Smørgrav 	if (options.kerberos_get_afs_token && k_hasafs() &&
16321ec0d754SDag-Erling Smørgrav 	    (s->authctxt->krb5_ctx != NULL)) {
16331ec0d754SDag-Erling Smørgrav 		char cell[64];
16341ec0d754SDag-Erling Smørgrav 
16351ec0d754SDag-Erling Smørgrav 		debug("Getting AFS token");
16361ec0d754SDag-Erling Smørgrav 
16371ec0d754SDag-Erling Smørgrav 		k_setpag();
16381ec0d754SDag-Erling Smørgrav 
16391ec0d754SDag-Erling Smørgrav 		if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
16401ec0d754SDag-Erling Smørgrav 			krb5_afslog(s->authctxt->krb5_ctx,
16411ec0d754SDag-Erling Smørgrav 			    s->authctxt->krb5_fwd_ccache, cell, NULL);
16421ec0d754SDag-Erling Smørgrav 
16431ec0d754SDag-Erling Smørgrav 		krb5_afslog_home(s->authctxt->krb5_ctx,
16441ec0d754SDag-Erling Smørgrav 		    s->authctxt->krb5_fwd_ccache, NULL, NULL, pw->pw_dir);
16451ec0d754SDag-Erling Smørgrav 	}
16461ec0d754SDag-Erling Smørgrav #endif
16471ec0d754SDag-Erling Smørgrav 
1648b74df5b2SDag-Erling Smørgrav 	/* Change current directory to the user's home directory. */
164919261079SEd Maste 	if (chdir(pw->pw_dir) == -1) {
1650d4af9e69SDag-Erling Smørgrav 		/* Suppress missing homedir warning for chroot case */
1651af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1652d4af9e69SDag-Erling Smørgrav 		r = login_getcapbool(lc, "requirehome", 0);
1653af12a3e7SDag-Erling Smørgrav #endif
1654acc1a9efSDag-Erling Smørgrav 		if (r || !in_chroot) {
1655d4af9e69SDag-Erling Smørgrav 			fprintf(stderr, "Could not chdir to home "
1656d4af9e69SDag-Erling Smørgrav 			    "directory %s: %s\n", pw->pw_dir,
1657d4af9e69SDag-Erling Smørgrav 			    strerror(errno));
1658acc1a9efSDag-Erling Smørgrav 		}
1659d4af9e69SDag-Erling Smørgrav 		if (r)
1660d4af9e69SDag-Erling Smørgrav 			exit(1);
1661af12a3e7SDag-Erling Smørgrav 	}
1662af12a3e7SDag-Erling Smørgrav 
1663d4af9e69SDag-Erling Smørgrav 	closefrom(STDERR_FILENO + 1);
1664d4af9e69SDag-Erling Smørgrav 
166547dd1d1bSDag-Erling Smørgrav 	do_rc_files(ssh, s, shell);
1666af12a3e7SDag-Erling Smørgrav 
1667ca3176e7SBrian Feldman 	/* restore SIGPIPE for child */
166819261079SEd Maste 	ssh_signal(SIGPIPE, SIG_DFL);
1669ca3176e7SBrian Feldman 
1670b15c8340SDag-Erling Smørgrav 	if (s->is_subsystem == SUBSYSTEM_INT_SFTP_ERROR) {
167119261079SEd Maste 		error("Connection from %s: refusing non-sftp session",
167219261079SEd Maste 		    remote_id);
1673b15c8340SDag-Erling Smørgrav 		printf("This service allows sftp connections only.\n");
1674b15c8340SDag-Erling Smørgrav 		fflush(NULL);
1675b15c8340SDag-Erling Smørgrav 		exit(1);
1676b15c8340SDag-Erling Smørgrav 	} else if (s->is_subsystem == SUBSYSTEM_INT_SFTP) {
1677d4af9e69SDag-Erling Smørgrav 		extern int optind, optreset;
1678d4af9e69SDag-Erling Smørgrav 		int i;
1679d4af9e69SDag-Erling Smørgrav 		char *p, *args;
1680d4af9e69SDag-Erling Smørgrav 
16817aee6ffeSDag-Erling Smørgrav 		setproctitle("%s@%s", s->pw->pw_name, INTERNAL_SFTP_NAME);
1682cce7d346SDag-Erling Smørgrav 		args = xstrdup(command ? command : "sftp-server");
1683d4af9e69SDag-Erling Smørgrav 		for (i = 0, (p = strtok(args, " ")); p; (p = strtok(NULL, " ")))
1684d4af9e69SDag-Erling Smørgrav 			if (i < ARGV_MAX - 1)
1685d4af9e69SDag-Erling Smørgrav 				argv[i++] = p;
1686d4af9e69SDag-Erling Smørgrav 		argv[i] = NULL;
1687d4af9e69SDag-Erling Smørgrav 		optind = optreset = 1;
1688d4af9e69SDag-Erling Smørgrav 		__progname = argv[0];
1689b15c8340SDag-Erling Smørgrav #ifdef WITH_SELINUX
1690b15c8340SDag-Erling Smørgrav 		ssh_selinux_change_context("sftpd_t");
1691b15c8340SDag-Erling Smørgrav #endif
1692d4af9e69SDag-Erling Smørgrav 		exit(sftp_server_main(i, argv, s->pw));
1693d4af9e69SDag-Erling Smørgrav 	}
1694d4af9e69SDag-Erling Smørgrav 
1695b15c8340SDag-Erling Smørgrav 	fflush(NULL);
1696b15c8340SDag-Erling Smørgrav 
1697af12a3e7SDag-Erling Smørgrav 	/* Get the last component of the shell name. */
1698af12a3e7SDag-Erling Smørgrav 	if ((shell0 = strrchr(shell, '/')) != NULL)
1699af12a3e7SDag-Erling Smørgrav 		shell0++;
1700af12a3e7SDag-Erling Smørgrav 	else
1701af12a3e7SDag-Erling Smørgrav 		shell0 = shell;
1702af12a3e7SDag-Erling Smørgrav 
1703a04a10f8SKris Kennaway 	/*
1704a04a10f8SKris Kennaway 	 * If we have no command, execute the shell.  In this case, the shell
1705a04a10f8SKris Kennaway 	 * name to be passed in argv[0] is preceded by '-' to indicate that
1706a04a10f8SKris Kennaway 	 * this is a login shell.
1707a04a10f8SKris Kennaway 	 */
1708a04a10f8SKris Kennaway 	if (!command) {
1709af12a3e7SDag-Erling Smørgrav 		char argv0[256];
1710a04a10f8SKris Kennaway 
1711a04a10f8SKris Kennaway 		/* Start the shell.  Set initial character to '-'. */
1712af12a3e7SDag-Erling Smørgrav 		argv0[0] = '-';
1713af12a3e7SDag-Erling Smørgrav 
1714af12a3e7SDag-Erling Smørgrav 		if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1)
1715af12a3e7SDag-Erling Smørgrav 		    >= sizeof(argv0) - 1) {
1716af12a3e7SDag-Erling Smørgrav 			errno = EINVAL;
1717af12a3e7SDag-Erling Smørgrav 			perror(shell);
1718af12a3e7SDag-Erling Smørgrav 			exit(1);
1719af12a3e7SDag-Erling Smørgrav 		}
1720a04a10f8SKris Kennaway 
1721a04a10f8SKris Kennaway 		/* Execute the shell. */
1722af12a3e7SDag-Erling Smørgrav 		argv[0] = argv0;
1723a04a10f8SKris Kennaway 		argv[1] = NULL;
1724a04a10f8SKris Kennaway 		execve(shell, argv, env);
1725a04a10f8SKris Kennaway 
1726a04a10f8SKris Kennaway 		/* Executing the shell failed. */
1727a04a10f8SKris Kennaway 		perror(shell);
1728a04a10f8SKris Kennaway 		exit(1);
1729a04a10f8SKris Kennaway 	}
1730a04a10f8SKris Kennaway 	/*
1731a04a10f8SKris Kennaway 	 * Execute the command using the user's shell.  This uses the -c
1732a04a10f8SKris Kennaway 	 * option to execute the command.
1733a04a10f8SKris Kennaway 	 */
1734af12a3e7SDag-Erling Smørgrav 	argv[0] = (char *) shell0;
1735a04a10f8SKris Kennaway 	argv[1] = "-c";
1736a04a10f8SKris Kennaway 	argv[2] = (char *) command;
1737a04a10f8SKris Kennaway 	argv[3] = NULL;
1738a04a10f8SKris Kennaway 	execve(shell, argv, env);
1739a04a10f8SKris Kennaway 	perror(shell);
1740a04a10f8SKris Kennaway 	exit(1);
1741a04a10f8SKris Kennaway }
1742a04a10f8SKris Kennaway 
1743d4af9e69SDag-Erling Smørgrav void
1744d4af9e69SDag-Erling Smørgrav session_unused(int id)
1745d4af9e69SDag-Erling Smørgrav {
174619261079SEd Maste 	debug3_f("session id %d unused", id);
1747d4af9e69SDag-Erling Smørgrav 	if (id >= options.max_sessions ||
1748d4af9e69SDag-Erling Smørgrav 	    id >= sessions_nalloc) {
174919261079SEd Maste 		fatal_f("insane session id %d (max %d nalloc %d)",
175019261079SEd Maste 		    id, options.max_sessions, sessions_nalloc);
1751d4af9e69SDag-Erling Smørgrav 	}
1752b83788ffSDag-Erling Smørgrav 	memset(&sessions[id], 0, sizeof(*sessions));
1753d4af9e69SDag-Erling Smørgrav 	sessions[id].self = id;
1754d4af9e69SDag-Erling Smørgrav 	sessions[id].used = 0;
1755d4af9e69SDag-Erling Smørgrav 	sessions[id].chanid = -1;
1756d4af9e69SDag-Erling Smørgrav 	sessions[id].ptyfd = -1;
1757d4af9e69SDag-Erling Smørgrav 	sessions[id].ttyfd = -1;
1758d4af9e69SDag-Erling Smørgrav 	sessions[id].ptymaster = -1;
1759d4af9e69SDag-Erling Smørgrav 	sessions[id].x11_chanids = NULL;
1760d4af9e69SDag-Erling Smørgrav 	sessions[id].next_unused = sessions_first_unused;
1761d4af9e69SDag-Erling Smørgrav 	sessions_first_unused = id;
1762d4af9e69SDag-Erling Smørgrav }
1763d4af9e69SDag-Erling Smørgrav 
1764a04a10f8SKris Kennaway Session *
1765a04a10f8SKris Kennaway session_new(void)
1766a04a10f8SKris Kennaway {
1767d4af9e69SDag-Erling Smørgrav 	Session *s, *tmp;
1768d4af9e69SDag-Erling Smørgrav 
1769d4af9e69SDag-Erling Smørgrav 	if (sessions_first_unused == -1) {
1770d4af9e69SDag-Erling Smørgrav 		if (sessions_nalloc >= options.max_sessions)
1771a04a10f8SKris Kennaway 			return NULL;
177219261079SEd Maste 		debug2_f("allocate (allocated %d max %d)",
177319261079SEd Maste 		    sessions_nalloc, options.max_sessions);
17744f52dfbbSDag-Erling Smørgrav 		tmp = xrecallocarray(sessions, sessions_nalloc,
17754f52dfbbSDag-Erling Smørgrav 		    sessions_nalloc + 1, sizeof(*sessions));
1776d4af9e69SDag-Erling Smørgrav 		if (tmp == NULL) {
177719261079SEd Maste 			error_f("cannot allocate %d sessions",
177819261079SEd Maste 			    sessions_nalloc + 1);
1779d4af9e69SDag-Erling Smørgrav 			return NULL;
1780d4af9e69SDag-Erling Smørgrav 		}
1781d4af9e69SDag-Erling Smørgrav 		sessions = tmp;
1782d4af9e69SDag-Erling Smørgrav 		session_unused(sessions_nalloc++);
1783d4af9e69SDag-Erling Smørgrav 	}
1784d4af9e69SDag-Erling Smørgrav 
1785d4af9e69SDag-Erling Smørgrav 	if (sessions_first_unused >= sessions_nalloc ||
1786d4af9e69SDag-Erling Smørgrav 	    sessions_first_unused < 0) {
178719261079SEd Maste 		fatal_f("insane first_unused %d max %d nalloc %d",
178819261079SEd Maste 		    sessions_first_unused, options.max_sessions,
1789d4af9e69SDag-Erling Smørgrav 		    sessions_nalloc);
1790d4af9e69SDag-Erling Smørgrav 	}
1791d4af9e69SDag-Erling Smørgrav 
1792d4af9e69SDag-Erling Smørgrav 	s = &sessions[sessions_first_unused];
179319261079SEd Maste 	if (s->used)
179419261079SEd Maste 		fatal_f("session %d already used", sessions_first_unused);
1795d4af9e69SDag-Erling Smørgrav 	sessions_first_unused = s->next_unused;
1796d4af9e69SDag-Erling Smørgrav 	s->used = 1;
1797d4af9e69SDag-Erling Smørgrav 	s->next_unused = -1;
1798d4af9e69SDag-Erling Smørgrav 	debug("session_new: session %d", s->self);
1799d4af9e69SDag-Erling Smørgrav 
1800d4af9e69SDag-Erling Smørgrav 	return s;
1801a04a10f8SKris Kennaway }
1802a04a10f8SKris Kennaway 
1803af12a3e7SDag-Erling Smørgrav static void
1804a04a10f8SKris Kennaway session_dump(void)
1805a04a10f8SKris Kennaway {
1806a04a10f8SKris Kennaway 	int i;
1807d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
1808a04a10f8SKris Kennaway 		Session *s = &sessions[i];
1809d4af9e69SDag-Erling Smørgrav 
181019261079SEd Maste 		debug("dump: used %d next_unused %d session %d "
1811d4af9e69SDag-Erling Smørgrav 		    "channel %d pid %ld",
1812a04a10f8SKris Kennaway 		    s->used,
1813d4af9e69SDag-Erling Smørgrav 		    s->next_unused,
1814a04a10f8SKris Kennaway 		    s->self,
1815a04a10f8SKris Kennaway 		    s->chanid,
181680628bacSDag-Erling Smørgrav 		    (long)s->pid);
1817a04a10f8SKris Kennaway 	}
1818a04a10f8SKris Kennaway }
1819a04a10f8SKris Kennaway 
1820a04a10f8SKris Kennaway int
1821af12a3e7SDag-Erling Smørgrav session_open(Authctxt *authctxt, int chanid)
1822a04a10f8SKris Kennaway {
1823a04a10f8SKris Kennaway 	Session *s = session_new();
1824a04a10f8SKris Kennaway 	debug("session_open: channel %d", chanid);
1825a04a10f8SKris Kennaway 	if (s == NULL) {
1826a04a10f8SKris Kennaway 		error("no more sessions");
1827a04a10f8SKris Kennaway 		return 0;
1828a04a10f8SKris Kennaway 	}
1829af12a3e7SDag-Erling Smørgrav 	s->authctxt = authctxt;
1830af12a3e7SDag-Erling Smørgrav 	s->pw = authctxt->pw;
18311ec0d754SDag-Erling Smørgrav 	if (s->pw == NULL || !authctxt->valid)
1832ca3176e7SBrian Feldman 		fatal("no user for session %d", s->self);
1833a04a10f8SKris Kennaway 	debug("session_open: session %d: link with channel %d", s->self, chanid);
1834a04a10f8SKris Kennaway 	s->chanid = chanid;
1835a04a10f8SKris Kennaway 	return 1;
1836a04a10f8SKris Kennaway }
1837a04a10f8SKris Kennaway 
183880628bacSDag-Erling Smørgrav Session *
183980628bacSDag-Erling Smørgrav session_by_tty(char *tty)
184080628bacSDag-Erling Smørgrav {
184180628bacSDag-Erling Smørgrav 	int i;
1842d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
184380628bacSDag-Erling Smørgrav 		Session *s = &sessions[i];
184480628bacSDag-Erling Smørgrav 		if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) {
184580628bacSDag-Erling Smørgrav 			debug("session_by_tty: session %d tty %s", i, tty);
184680628bacSDag-Erling Smørgrav 			return s;
184780628bacSDag-Erling Smørgrav 		}
184880628bacSDag-Erling Smørgrav 	}
184980628bacSDag-Erling Smørgrav 	debug("session_by_tty: unknown tty %.100s", tty);
185080628bacSDag-Erling Smørgrav 	session_dump();
185180628bacSDag-Erling Smørgrav 	return NULL;
185280628bacSDag-Erling Smørgrav }
185380628bacSDag-Erling Smørgrav 
1854af12a3e7SDag-Erling Smørgrav static Session *
1855a04a10f8SKris Kennaway session_by_channel(int id)
1856a04a10f8SKris Kennaway {
1857a04a10f8SKris Kennaway 	int i;
1858d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
1859a04a10f8SKris Kennaway 		Session *s = &sessions[i];
1860a04a10f8SKris Kennaway 		if (s->used && s->chanid == id) {
1861d4af9e69SDag-Erling Smørgrav 			debug("session_by_channel: session %d channel %d",
1862d4af9e69SDag-Erling Smørgrav 			    i, id);
1863a04a10f8SKris Kennaway 			return s;
1864a04a10f8SKris Kennaway 		}
1865a04a10f8SKris Kennaway 	}
1866a04a10f8SKris Kennaway 	debug("session_by_channel: unknown channel %d", id);
1867a04a10f8SKris Kennaway 	session_dump();
1868a04a10f8SKris Kennaway 	return NULL;
1869a04a10f8SKris Kennaway }
1870a04a10f8SKris Kennaway 
1871af12a3e7SDag-Erling Smørgrav static Session *
1872d4ecd108SDag-Erling Smørgrav session_by_x11_channel(int id)
1873d4ecd108SDag-Erling Smørgrav {
1874d4ecd108SDag-Erling Smørgrav 	int i, j;
1875d4ecd108SDag-Erling Smørgrav 
1876d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
1877d4ecd108SDag-Erling Smørgrav 		Session *s = &sessions[i];
1878d4ecd108SDag-Erling Smørgrav 
1879d4ecd108SDag-Erling Smørgrav 		if (s->x11_chanids == NULL || !s->used)
1880d4ecd108SDag-Erling Smørgrav 			continue;
1881d4ecd108SDag-Erling Smørgrav 		for (j = 0; s->x11_chanids[j] != -1; j++) {
1882d4ecd108SDag-Erling Smørgrav 			if (s->x11_chanids[j] == id) {
1883d4ecd108SDag-Erling Smørgrav 				debug("session_by_x11_channel: session %d "
1884d4ecd108SDag-Erling Smørgrav 				    "channel %d", s->self, id);
1885d4ecd108SDag-Erling Smørgrav 				return s;
1886d4ecd108SDag-Erling Smørgrav 			}
1887d4ecd108SDag-Erling Smørgrav 		}
1888d4ecd108SDag-Erling Smørgrav 	}
1889d4ecd108SDag-Erling Smørgrav 	debug("session_by_x11_channel: unknown channel %d", id);
1890d4ecd108SDag-Erling Smørgrav 	session_dump();
1891d4ecd108SDag-Erling Smørgrav 	return NULL;
1892d4ecd108SDag-Erling Smørgrav }
1893d4ecd108SDag-Erling Smørgrav 
1894d4ecd108SDag-Erling Smørgrav static Session *
1895a04a10f8SKris Kennaway session_by_pid(pid_t pid)
1896a04a10f8SKris Kennaway {
1897a04a10f8SKris Kennaway 	int i;
189880628bacSDag-Erling Smørgrav 	debug("session_by_pid: pid %ld", (long)pid);
1899d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
1900a04a10f8SKris Kennaway 		Session *s = &sessions[i];
1901a04a10f8SKris Kennaway 		if (s->used && s->pid == pid)
1902a04a10f8SKris Kennaway 			return s;
1903a04a10f8SKris Kennaway 	}
190480628bacSDag-Erling Smørgrav 	error("session_by_pid: unknown pid %ld", (long)pid);
1905a04a10f8SKris Kennaway 	session_dump();
1906a04a10f8SKris Kennaway 	return NULL;
1907a04a10f8SKris Kennaway }
1908a04a10f8SKris Kennaway 
1909af12a3e7SDag-Erling Smørgrav static int
19104f52dfbbSDag-Erling Smørgrav session_window_change_req(struct ssh *ssh, Session *s)
1911a04a10f8SKris Kennaway {
191219261079SEd Maste 	int r;
191319261079SEd Maste 
191419261079SEd Maste 	if ((r = sshpkt_get_u32(ssh, &s->col)) != 0 ||
191519261079SEd Maste 	    (r = sshpkt_get_u32(ssh, &s->row)) != 0 ||
191619261079SEd Maste 	    (r = sshpkt_get_u32(ssh, &s->xpixel)) != 0 ||
191719261079SEd Maste 	    (r = sshpkt_get_u32(ssh, &s->ypixel)) != 0 ||
191819261079SEd Maste 	    (r = sshpkt_get_end(ssh)) != 0)
191919261079SEd Maste 		sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
1920a04a10f8SKris Kennaway 	pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
1921a04a10f8SKris Kennaway 	return 1;
1922a04a10f8SKris Kennaway }
1923a04a10f8SKris Kennaway 
1924af12a3e7SDag-Erling Smørgrav static int
19254f52dfbbSDag-Erling Smørgrav session_pty_req(struct ssh *ssh, Session *s)
1926a04a10f8SKris Kennaway {
192719261079SEd Maste 	int r;
1928a04a10f8SKris Kennaway 
192947dd1d1bSDag-Erling Smørgrav 	if (!auth_opts->permit_pty_flag || !options.permit_tty) {
193047dd1d1bSDag-Erling Smørgrav 		debug("Allocating a pty not permitted for this connection.");
1931c2d3a559SKris Kennaway 		return 0;
1932af12a3e7SDag-Erling Smørgrav 	}
1933af12a3e7SDag-Erling Smørgrav 	if (s->ttyfd != -1) {
193419261079SEd Maste 		ssh_packet_disconnect(ssh, "Protocol error: you already have a pty.");
1935a04a10f8SKris Kennaway 		return 0;
1936af12a3e7SDag-Erling Smørgrav 	}
1937af12a3e7SDag-Erling Smørgrav 
193819261079SEd Maste 	if ((r = sshpkt_get_cstring(ssh, &s->term, NULL)) != 0 ||
193919261079SEd Maste 	    (r = sshpkt_get_u32(ssh, &s->col)) != 0 ||
194019261079SEd Maste 	    (r = sshpkt_get_u32(ssh, &s->row)) != 0 ||
194119261079SEd Maste 	    (r = sshpkt_get_u32(ssh, &s->xpixel)) != 0 ||
194219261079SEd Maste 	    (r = sshpkt_get_u32(ssh, &s->ypixel)) != 0)
194319261079SEd Maste 		sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
1944a04a10f8SKris Kennaway 
1945a04a10f8SKris Kennaway 	if (strcmp(s->term, "") == 0) {
1946e4a9863fSDag-Erling Smørgrav 		free(s->term);
1947a04a10f8SKris Kennaway 		s->term = NULL;
1948a04a10f8SKris Kennaway 	}
1949af12a3e7SDag-Erling Smørgrav 
1950a04a10f8SKris Kennaway 	/* Allocate a pty and open it. */
1951af12a3e7SDag-Erling Smørgrav 	debug("Allocating pty.");
1952d4af9e69SDag-Erling Smørgrav 	if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty,
1953d4af9e69SDag-Erling Smørgrav 	    sizeof(s->tty)))) {
1954e4a9863fSDag-Erling Smørgrav 		free(s->term);
1955a04a10f8SKris Kennaway 		s->term = NULL;
1956a04a10f8SKris Kennaway 		s->ptyfd = -1;
1957a04a10f8SKris Kennaway 		s->ttyfd = -1;
1958a04a10f8SKris Kennaway 		error("session_pty_req: session %d alloc failed", s->self);
1959a04a10f8SKris Kennaway 		return 0;
1960a04a10f8SKris Kennaway 	}
1961a04a10f8SKris Kennaway 	debug("session_pty_req: session %d alloc %s", s->self, s->tty);
1962af12a3e7SDag-Erling Smørgrav 
1963190cef3dSDag-Erling Smørgrav 	ssh_tty_parse_modes(ssh, s->ttyfd);
1964af12a3e7SDag-Erling Smørgrav 
196519261079SEd Maste 	if ((r = sshpkt_get_end(ssh)) != 0)
196619261079SEd Maste 		sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
196719261079SEd Maste 
196880628bacSDag-Erling Smørgrav 	if (!use_privsep)
1969a04a10f8SKris Kennaway 		pty_setowner(s->pw, s->tty);
1970af12a3e7SDag-Erling Smørgrav 
1971af12a3e7SDag-Erling Smørgrav 	/* Set window size from the packet. */
1972a04a10f8SKris Kennaway 	pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
1973a04a10f8SKris Kennaway 
1974a04a10f8SKris Kennaway 	session_proctitle(s);
1975a04a10f8SKris Kennaway 	return 1;
1976a04a10f8SKris Kennaway }
1977a04a10f8SKris Kennaway 
1978af12a3e7SDag-Erling Smørgrav static int
19794f52dfbbSDag-Erling Smørgrav session_subsystem_req(struct ssh *ssh, Session *s)
1980a04a10f8SKris Kennaway {
1981af12a3e7SDag-Erling Smørgrav 	struct stat st;
198219261079SEd Maste 	int r, success = 0;
1983f7167e0eSDag-Erling Smørgrav 	char *prog, *cmd;
1984d4ecd108SDag-Erling Smørgrav 	u_int i;
1985a04a10f8SKris Kennaway 
198619261079SEd Maste 	if ((r = sshpkt_get_cstring(ssh, &s->subsys, NULL)) != 0 ||
198719261079SEd Maste 	    (r = sshpkt_get_end(ssh)) != 0)
198819261079SEd Maste 		sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
1989f7167e0eSDag-Erling Smørgrav 	debug2("subsystem request for %.100s by user %s", s->subsys,
1990e2f6069cSDag-Erling Smørgrav 	    s->pw->pw_name);
1991a04a10f8SKris Kennaway 
1992c2d3a559SKris Kennaway 	for (i = 0; i < options.num_subsystems; i++) {
1993f7167e0eSDag-Erling Smørgrav 		if (strcmp(s->subsys, options.subsystem_name[i]) == 0) {
1994333ee039SDag-Erling Smørgrav 			prog = options.subsystem_command[i];
1995333ee039SDag-Erling Smørgrav 			cmd = options.subsystem_args[i];
1996b15c8340SDag-Erling Smørgrav 			if (strcmp(INTERNAL_SFTP_NAME, prog) == 0) {
1997d4af9e69SDag-Erling Smørgrav 				s->is_subsystem = SUBSYSTEM_INT_SFTP;
1998b15c8340SDag-Erling Smørgrav 				debug("subsystem: %s", prog);
1999d4af9e69SDag-Erling Smørgrav 			} else {
200019261079SEd Maste 				if (stat(prog, &st) == -1)
2001b15c8340SDag-Erling Smørgrav 					debug("subsystem: cannot stat %s: %s",
2002b15c8340SDag-Erling Smørgrav 					    prog, strerror(errno));
2003d4af9e69SDag-Erling Smørgrav 				s->is_subsystem = SUBSYSTEM_EXT;
2004af12a3e7SDag-Erling Smørgrav 				debug("subsystem: exec() %s", cmd);
2005b15c8340SDag-Erling Smørgrav 			}
20064f52dfbbSDag-Erling Smørgrav 			success = do_exec(ssh, s, cmd) == 0;
2007af12a3e7SDag-Erling Smørgrav 			break;
2008c2d3a559SKris Kennaway 		}
2009c2d3a559SKris Kennaway 	}
2010c2d3a559SKris Kennaway 
2011c2d3a559SKris Kennaway 	if (!success)
2012f7167e0eSDag-Erling Smørgrav 		logit("subsystem request for %.100s by user %s failed, "
2013f7167e0eSDag-Erling Smørgrav 		    "subsystem not found", s->subsys, s->pw->pw_name);
2014c2d3a559SKris Kennaway 
2015a04a10f8SKris Kennaway 	return success;
2016a04a10f8SKris Kennaway }
2017a04a10f8SKris Kennaway 
2018af12a3e7SDag-Erling Smørgrav static int
20194f52dfbbSDag-Erling Smørgrav session_x11_req(struct ssh *ssh, Session *s)
2020a04a10f8SKris Kennaway {
202119261079SEd Maste 	int r, success;
202219261079SEd Maste 	u_char single_connection = 0;
2023a04a10f8SKris Kennaway 
2024d4ecd108SDag-Erling Smørgrav 	if (s->auth_proto != NULL || s->auth_data != NULL) {
2025d4ecd108SDag-Erling Smørgrav 		error("session_x11_req: session %d: "
2026b74df5b2SDag-Erling Smørgrav 		    "x11 forwarding already active", s->self);
2027d4ecd108SDag-Erling Smørgrav 		return 0;
2028d4ecd108SDag-Erling Smørgrav 	}
202919261079SEd Maste 	if ((r = sshpkt_get_u8(ssh, &single_connection)) != 0 ||
203019261079SEd Maste 	    (r = sshpkt_get_cstring(ssh, &s->auth_proto, NULL)) != 0 ||
203119261079SEd Maste 	    (r = sshpkt_get_cstring(ssh, &s->auth_data, NULL)) != 0 ||
203219261079SEd Maste 	    (r = sshpkt_get_u32(ssh, &s->screen)) != 0 ||
203319261079SEd Maste 	    (r = sshpkt_get_end(ssh)) != 0)
203419261079SEd Maste 		sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
203519261079SEd Maste 
203619261079SEd Maste 	s->single_connection = single_connection;
2037a04a10f8SKris Kennaway 
2038acc1a9efSDag-Erling Smørgrav 	if (xauth_valid_string(s->auth_proto) &&
2039acc1a9efSDag-Erling Smørgrav 	    xauth_valid_string(s->auth_data))
20404f52dfbbSDag-Erling Smørgrav 		success = session_setup_x11fwd(ssh, s);
2041acc1a9efSDag-Erling Smørgrav 	else {
2042acc1a9efSDag-Erling Smørgrav 		success = 0;
2043acc1a9efSDag-Erling Smørgrav 		error("Invalid X11 forwarding data");
2044acc1a9efSDag-Erling Smørgrav 	}
2045af12a3e7SDag-Erling Smørgrav 	if (!success) {
2046e4a9863fSDag-Erling Smørgrav 		free(s->auth_proto);
2047e4a9863fSDag-Erling Smørgrav 		free(s->auth_data);
2048af12a3e7SDag-Erling Smørgrav 		s->auth_proto = NULL;
2049af12a3e7SDag-Erling Smørgrav 		s->auth_data = NULL;
2050a04a10f8SKris Kennaway 	}
2051af12a3e7SDag-Erling Smørgrav 	return success;
2052a04a10f8SKris Kennaway }
2053a04a10f8SKris Kennaway 
2054af12a3e7SDag-Erling Smørgrav static int
20554f52dfbbSDag-Erling Smørgrav session_shell_req(struct ssh *ssh, Session *s)
2056c2d3a559SKris Kennaway {
205719261079SEd Maste 	int r;
205819261079SEd Maste 
205919261079SEd Maste 	if ((r = sshpkt_get_end(ssh)) != 0)
206019261079SEd Maste 		sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
20614f52dfbbSDag-Erling Smørgrav 	return do_exec(ssh, s, NULL) == 0;
2062c2d3a559SKris Kennaway }
2063c2d3a559SKris Kennaway 
2064af12a3e7SDag-Erling Smørgrav static int
20654f52dfbbSDag-Erling Smørgrav session_exec_req(struct ssh *ssh, Session *s)
2066c2d3a559SKris Kennaway {
206719261079SEd Maste 	u_int success;
206819261079SEd Maste 	int r;
206919261079SEd Maste 	char *command = NULL;
2070d4af9e69SDag-Erling Smørgrav 
207119261079SEd Maste 	if ((r = sshpkt_get_cstring(ssh, &command, NULL)) != 0 ||
207219261079SEd Maste 	    (r = sshpkt_get_end(ssh)) != 0)
207319261079SEd Maste 		sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
207419261079SEd Maste 
20754f52dfbbSDag-Erling Smørgrav 	success = do_exec(ssh, s, command) == 0;
2076e4a9863fSDag-Erling Smørgrav 	free(command);
2077d4af9e69SDag-Erling Smørgrav 	return success;
2078c2d3a559SKris Kennaway }
2079c2d3a559SKris Kennaway 
2080af12a3e7SDag-Erling Smørgrav static int
20814f52dfbbSDag-Erling Smørgrav session_break_req(struct ssh *ssh, Session *s)
2082cf2b5f3bSDag-Erling Smørgrav {
208319261079SEd Maste 	int r;
2084cf2b5f3bSDag-Erling Smørgrav 
208519261079SEd Maste 	if ((r = sshpkt_get_u32(ssh, NULL)) != 0 || /* ignore */
208619261079SEd Maste 	    (r = sshpkt_get_end(ssh)) != 0)
208719261079SEd Maste 		sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
2088cf2b5f3bSDag-Erling Smørgrav 
208919261079SEd Maste 	if (s->ptymaster == -1 || tcsendbreak(s->ptymaster, 0) == -1)
2090cf2b5f3bSDag-Erling Smørgrav 		return 0;
2091cf2b5f3bSDag-Erling Smørgrav 	return 1;
2092cf2b5f3bSDag-Erling Smørgrav }
2093cf2b5f3bSDag-Erling Smørgrav 
2094cf2b5f3bSDag-Erling Smørgrav static int
20954f52dfbbSDag-Erling Smørgrav session_env_req(struct ssh *ssh, Session *s)
209621e764dfSDag-Erling Smørgrav {
209721e764dfSDag-Erling Smørgrav 	char *name, *val;
209819261079SEd Maste 	u_int i;
209919261079SEd Maste 	int r;
210021e764dfSDag-Erling Smørgrav 
210119261079SEd Maste 	if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0 ||
210219261079SEd Maste 	    (r = sshpkt_get_cstring(ssh, &val, NULL)) != 0 ||
210319261079SEd Maste 	    (r = sshpkt_get_end(ssh)) != 0)
210419261079SEd Maste 		sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
210521e764dfSDag-Erling Smørgrav 
210621e764dfSDag-Erling Smørgrav 	/* Don't set too many environment variables */
210721e764dfSDag-Erling Smørgrav 	if (s->num_env > 128) {
210821e764dfSDag-Erling Smørgrav 		debug2("Ignoring env request %s: too many env vars", name);
210921e764dfSDag-Erling Smørgrav 		goto fail;
211021e764dfSDag-Erling Smørgrav 	}
211121e764dfSDag-Erling Smørgrav 
211221e764dfSDag-Erling Smørgrav 	for (i = 0; i < options.num_accept_env; i++) {
211321e764dfSDag-Erling Smørgrav 		if (match_pattern(name, options.accept_env[i])) {
211421e764dfSDag-Erling Smørgrav 			debug2("Setting env %d: %s=%s", s->num_env, name, val);
21154f52dfbbSDag-Erling Smørgrav 			s->env = xrecallocarray(s->env, s->num_env,
21164f52dfbbSDag-Erling Smørgrav 			    s->num_env + 1, sizeof(*s->env));
211721e764dfSDag-Erling Smørgrav 			s->env[s->num_env].name = name;
211821e764dfSDag-Erling Smørgrav 			s->env[s->num_env].val = val;
211921e764dfSDag-Erling Smørgrav 			s->num_env++;
212021e764dfSDag-Erling Smørgrav 			return (1);
212121e764dfSDag-Erling Smørgrav 		}
212221e764dfSDag-Erling Smørgrav 	}
212321e764dfSDag-Erling Smørgrav 	debug2("Ignoring env request %s: disallowed name", name);
212421e764dfSDag-Erling Smørgrav 
212521e764dfSDag-Erling Smørgrav  fail:
2126e4a9863fSDag-Erling Smørgrav 	free(name);
2127e4a9863fSDag-Erling Smørgrav 	free(val);
212821e764dfSDag-Erling Smørgrav 	return (0);
212921e764dfSDag-Erling Smørgrav }
213021e764dfSDag-Erling Smørgrav 
21312f513db7SEd Maste /*
21322f513db7SEd Maste  * Conversion of signals from ssh channel request names.
21332f513db7SEd Maste  * Subset of signals from RFC 4254 section 6.10C, with SIGINFO as
21342f513db7SEd Maste  * local extension.
21352f513db7SEd Maste  */
21362f513db7SEd Maste static int
21372f513db7SEd Maste name2sig(char *name)
21382f513db7SEd Maste {
21392f513db7SEd Maste #define SSH_SIG(x) if (strcmp(name, #x) == 0) return SIG ## x
21402f513db7SEd Maste 	SSH_SIG(HUP);
21412f513db7SEd Maste 	SSH_SIG(INT);
21422f513db7SEd Maste 	SSH_SIG(KILL);
21432f513db7SEd Maste 	SSH_SIG(QUIT);
21442f513db7SEd Maste 	SSH_SIG(TERM);
21452f513db7SEd Maste 	SSH_SIG(USR1);
21462f513db7SEd Maste 	SSH_SIG(USR2);
21472f513db7SEd Maste #undef	SSH_SIG
21482f513db7SEd Maste #ifdef SIGINFO
21492f513db7SEd Maste 	if (strcmp(name, "INFO@openssh.com") == 0)
21502f513db7SEd Maste 		return SIGINFO;
21512f513db7SEd Maste #endif
21522f513db7SEd Maste 	return -1;
21532f513db7SEd Maste }
21542f513db7SEd Maste 
21552f513db7SEd Maste static int
21562f513db7SEd Maste session_signal_req(struct ssh *ssh, Session *s)
21572f513db7SEd Maste {
21582f513db7SEd Maste 	char *signame = NULL;
21592f513db7SEd Maste 	int r, sig, success = 0;
21602f513db7SEd Maste 
21612f513db7SEd Maste 	if ((r = sshpkt_get_cstring(ssh, &signame, NULL)) != 0 ||
21622f513db7SEd Maste 	    (r = sshpkt_get_end(ssh)) != 0) {
216319261079SEd Maste 		error_fr(r, "parse");
21642f513db7SEd Maste 		goto out;
21652f513db7SEd Maste 	}
21662f513db7SEd Maste 	if ((sig = name2sig(signame)) == -1) {
216719261079SEd Maste 		error_f("unsupported signal \"%s\"", signame);
21682f513db7SEd Maste 		goto out;
21692f513db7SEd Maste 	}
21702f513db7SEd Maste 	if (s->pid <= 0) {
217119261079SEd Maste 		error_f("no pid for session %d", s->self);
21722f513db7SEd Maste 		goto out;
21732f513db7SEd Maste 	}
21742f513db7SEd Maste 	if (s->forced || s->is_subsystem) {
217519261079SEd Maste 		error_f("refusing to send signal %s to %s session",
21762f513db7SEd Maste 		    signame, s->forced ? "forced-command" : "subsystem");
21772f513db7SEd Maste 		goto out;
21782f513db7SEd Maste 	}
21792f513db7SEd Maste 	if (!use_privsep || mm_is_monitor()) {
218019261079SEd Maste 		error_f("session signalling requires privilege separation");
21812f513db7SEd Maste 		goto out;
21822f513db7SEd Maste 	}
21832f513db7SEd Maste 
218419261079SEd Maste 	debug_f("signal %s, killpg(%ld, %d)", signame, (long)s->pid, sig);
21852f513db7SEd Maste 	temporarily_use_uid(s->pw);
21862f513db7SEd Maste 	r = killpg(s->pid, sig);
21872f513db7SEd Maste 	restore_uid();
21882f513db7SEd Maste 	if (r != 0) {
218919261079SEd Maste 		error_f("killpg(%ld, %d): %s", (long)s->pid,
21902f513db7SEd Maste 		    sig, strerror(errno));
21912f513db7SEd Maste 		goto out;
21922f513db7SEd Maste 	}
21932f513db7SEd Maste 
21942f513db7SEd Maste 	/* success */
21952f513db7SEd Maste 	success = 1;
21962f513db7SEd Maste  out:
21972f513db7SEd Maste 	free(signame);
21982f513db7SEd Maste 	return success;
21992f513db7SEd Maste }
22002f513db7SEd Maste 
220121e764dfSDag-Erling Smørgrav static int
22024f52dfbbSDag-Erling Smørgrav session_auth_agent_req(struct ssh *ssh, Session *s)
2203ca3176e7SBrian Feldman {
2204ca3176e7SBrian Feldman 	static int called = 0;
220519261079SEd Maste 	int r;
220647dd1d1bSDag-Erling Smørgrav 
220719261079SEd Maste 	if ((r = sshpkt_get_end(ssh)) != 0)
220819261079SEd Maste 		sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
220947dd1d1bSDag-Erling Smørgrav 	if (!auth_opts->permit_agent_forwarding_flag ||
221047dd1d1bSDag-Erling Smørgrav 	    !options.allow_agent_forwarding) {
221119261079SEd Maste 		debug_f("agent forwarding disabled");
2212ca3176e7SBrian Feldman 		return 0;
2213ca3176e7SBrian Feldman 	}
2214ca3176e7SBrian Feldman 	if (called) {
2215ca3176e7SBrian Feldman 		return 0;
2216ca3176e7SBrian Feldman 	} else {
2217ca3176e7SBrian Feldman 		called = 1;
22184f52dfbbSDag-Erling Smørgrav 		return auth_input_request_forwarding(ssh, s->pw);
2219ca3176e7SBrian Feldman 	}
2220ca3176e7SBrian Feldman }
2221ca3176e7SBrian Feldman 
2222af12a3e7SDag-Erling Smørgrav int
22234f52dfbbSDag-Erling Smørgrav session_input_channel_req(struct ssh *ssh, Channel *c, const char *rtype)
2224a04a10f8SKris Kennaway {
2225a04a10f8SKris Kennaway 	int success = 0;
2226a04a10f8SKris Kennaway 	Session *s;
2227a04a10f8SKris Kennaway 
2228af12a3e7SDag-Erling Smørgrav 	if ((s = session_by_channel(c->self)) == NULL) {
222919261079SEd Maste 		logit_f("no session %d req %.100s", c->self, rtype);
2230af12a3e7SDag-Erling Smørgrav 		return 0;
2231af12a3e7SDag-Erling Smørgrav 	}
223219261079SEd Maste 	debug_f("session %d req %s", s->self, rtype);
2233a04a10f8SKris Kennaway 
2234a04a10f8SKris Kennaway 	/*
2235ca3176e7SBrian Feldman 	 * a session is in LARVAL state until a shell, a command
2236ca3176e7SBrian Feldman 	 * or a subsystem is executed
2237a04a10f8SKris Kennaway 	 */
2238a04a10f8SKris Kennaway 	if (c->type == SSH_CHANNEL_LARVAL) {
2239a04a10f8SKris Kennaway 		if (strcmp(rtype, "shell") == 0) {
22404f52dfbbSDag-Erling Smørgrav 			success = session_shell_req(ssh, s);
2241a04a10f8SKris Kennaway 		} else if (strcmp(rtype, "exec") == 0) {
22424f52dfbbSDag-Erling Smørgrav 			success = session_exec_req(ssh, s);
2243a04a10f8SKris Kennaway 		} else if (strcmp(rtype, "pty-req") == 0) {
22444f52dfbbSDag-Erling Smørgrav 			success = session_pty_req(ssh, s);
2245a04a10f8SKris Kennaway 		} else if (strcmp(rtype, "x11-req") == 0) {
22464f52dfbbSDag-Erling Smørgrav 			success = session_x11_req(ssh, s);
2247ca3176e7SBrian Feldman 		} else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) {
22484f52dfbbSDag-Erling Smørgrav 			success = session_auth_agent_req(ssh, s);
2249a04a10f8SKris Kennaway 		} else if (strcmp(rtype, "subsystem") == 0) {
22504f52dfbbSDag-Erling Smørgrav 			success = session_subsystem_req(ssh, s);
225121e764dfSDag-Erling Smørgrav 		} else if (strcmp(rtype, "env") == 0) {
22524f52dfbbSDag-Erling Smørgrav 			success = session_env_req(ssh, s);
2253a04a10f8SKris Kennaway 		}
2254a04a10f8SKris Kennaway 	}
2255a04a10f8SKris Kennaway 	if (strcmp(rtype, "window-change") == 0) {
22564f52dfbbSDag-Erling Smørgrav 		success = session_window_change_req(ssh, s);
225721e764dfSDag-Erling Smørgrav 	} else if (strcmp(rtype, "break") == 0) {
22584f52dfbbSDag-Erling Smørgrav 		success = session_break_req(ssh, s);
22592f513db7SEd Maste 	} else if (strcmp(rtype, "signal") == 0) {
22602f513db7SEd Maste 		success = session_signal_req(ssh, s);
2261a04a10f8SKris Kennaway 	}
226221e764dfSDag-Erling Smørgrav 
2263af12a3e7SDag-Erling Smørgrav 	return success;
2264a04a10f8SKris Kennaway }
2265a04a10f8SKris Kennaway 
2266a04a10f8SKris Kennaway void
22674f52dfbbSDag-Erling Smørgrav session_set_fds(struct ssh *ssh, Session *s,
22684f52dfbbSDag-Erling Smørgrav     int fdin, int fdout, int fderr, int ignore_fderr, int is_tty)
2269a04a10f8SKris Kennaway {
2270a04a10f8SKris Kennaway 	/*
2271a04a10f8SKris Kennaway 	 * now that have a child and a pipe to the child,
2272a04a10f8SKris Kennaway 	 * we can activate our channel and register the fd's
2273a04a10f8SKris Kennaway 	 */
2274a04a10f8SKris Kennaway 	if (s->chanid == -1)
2275a04a10f8SKris Kennaway 		fatal("no channel for session %d", s->self);
22764f52dfbbSDag-Erling Smørgrav 	channel_set_fds(ssh, s->chanid,
227760c59fadSDag-Erling Smørgrav 	    fdout, fdin, fderr,
2278e2f6069cSDag-Erling Smørgrav 	    ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
2279d4af9e69SDag-Erling Smørgrav 	    1, is_tty, CHAN_SES_WINDOW_DEFAULT);
2280a04a10f8SKris Kennaway }
2281a04a10f8SKris Kennaway 
2282af12a3e7SDag-Erling Smørgrav /*
2283af12a3e7SDag-Erling Smørgrav  * Function to perform pty cleanup. Also called if we get aborted abnormally
2284af12a3e7SDag-Erling Smørgrav  * (e.g., due to a dropped connection).
2285af12a3e7SDag-Erling Smørgrav  */
228680628bacSDag-Erling Smørgrav void
22871ec0d754SDag-Erling Smørgrav session_pty_cleanup2(Session *s)
2288a04a10f8SKris Kennaway {
2289af12a3e7SDag-Erling Smørgrav 	if (s == NULL) {
229019261079SEd Maste 		error_f("no session");
2291af12a3e7SDag-Erling Smørgrav 		return;
2292af12a3e7SDag-Erling Smørgrav 	}
2293af12a3e7SDag-Erling Smørgrav 	if (s->ttyfd == -1)
2294a04a10f8SKris Kennaway 		return;
2295a04a10f8SKris Kennaway 
229619261079SEd Maste 	debug_f("session %d release %s", s->self, s->tty);
2297a04a10f8SKris Kennaway 
2298a04a10f8SKris Kennaway 	/* Record that the user has logged out. */
2299af12a3e7SDag-Erling Smørgrav 	if (s->pid != 0)
2300989dd127SDag-Erling Smørgrav 		record_logout(s->pid, s->tty, s->pw->pw_name);
2301a04a10f8SKris Kennaway 
2302a04a10f8SKris Kennaway 	/* Release the pseudo-tty. */
230380628bacSDag-Erling Smørgrav 	if (getuid() == 0)
2304a04a10f8SKris Kennaway 		pty_release(s->tty);
2305a04a10f8SKris Kennaway 
2306a04a10f8SKris Kennaway 	/*
2307a04a10f8SKris Kennaway 	 * Close the server side of the socket pairs.  We must do this after
2308a04a10f8SKris Kennaway 	 * the pty cleanup, so that another process doesn't get this pty
2309a04a10f8SKris Kennaway 	 * while we're still cleaning up.
2310a04a10f8SKris Kennaway 	 */
231119261079SEd Maste 	if (s->ptymaster != -1 && close(s->ptymaster) == -1)
2312d4af9e69SDag-Erling Smørgrav 		error("close(s->ptymaster/%d): %s",
2313d4af9e69SDag-Erling Smørgrav 		    s->ptymaster, strerror(errno));
2314af12a3e7SDag-Erling Smørgrav 
2315af12a3e7SDag-Erling Smørgrav 	/* unlink pty from session */
2316af12a3e7SDag-Erling Smørgrav 	s->ttyfd = -1;
2317a04a10f8SKris Kennaway }
2318a04a10f8SKris Kennaway 
231980628bacSDag-Erling Smørgrav void
23201ec0d754SDag-Erling Smørgrav session_pty_cleanup(Session *s)
232180628bacSDag-Erling Smørgrav {
23221ec0d754SDag-Erling Smørgrav 	PRIVSEP(session_pty_cleanup2(s));
232380628bacSDag-Erling Smørgrav }
232480628bacSDag-Erling Smørgrav 
2325f388f5efSDag-Erling Smørgrav static char *
2326f388f5efSDag-Erling Smørgrav sig2name(int sig)
2327f388f5efSDag-Erling Smørgrav {
2328f388f5efSDag-Erling Smørgrav #define SSH_SIG(x) if (sig == SIG ## x) return #x
2329f388f5efSDag-Erling Smørgrav 	SSH_SIG(ABRT);
2330f388f5efSDag-Erling Smørgrav 	SSH_SIG(ALRM);
2331f388f5efSDag-Erling Smørgrav 	SSH_SIG(FPE);
2332f388f5efSDag-Erling Smørgrav 	SSH_SIG(HUP);
2333f388f5efSDag-Erling Smørgrav 	SSH_SIG(ILL);
2334f388f5efSDag-Erling Smørgrav 	SSH_SIG(INT);
2335f388f5efSDag-Erling Smørgrav 	SSH_SIG(KILL);
2336f388f5efSDag-Erling Smørgrav 	SSH_SIG(PIPE);
2337f388f5efSDag-Erling Smørgrav 	SSH_SIG(QUIT);
2338f388f5efSDag-Erling Smørgrav 	SSH_SIG(SEGV);
2339f388f5efSDag-Erling Smørgrav 	SSH_SIG(TERM);
2340f388f5efSDag-Erling Smørgrav 	SSH_SIG(USR1);
2341f388f5efSDag-Erling Smørgrav 	SSH_SIG(USR2);
2342f388f5efSDag-Erling Smørgrav #undef	SSH_SIG
2343f388f5efSDag-Erling Smørgrav 	return "SIG@openssh.com";
2344f388f5efSDag-Erling Smørgrav }
2345f388f5efSDag-Erling Smørgrav 
2346af12a3e7SDag-Erling Smørgrav static void
23474f52dfbbSDag-Erling Smørgrav session_close_x11(struct ssh *ssh, int id)
2348d4ecd108SDag-Erling Smørgrav {
2349d4ecd108SDag-Erling Smørgrav 	Channel *c;
2350d4ecd108SDag-Erling Smørgrav 
23514f52dfbbSDag-Erling Smørgrav 	if ((c = channel_by_id(ssh, id)) == NULL) {
235219261079SEd Maste 		debug_f("x11 channel %d missing", id);
2353d4ecd108SDag-Erling Smørgrav 	} else {
2354d4ecd108SDag-Erling Smørgrav 		/* Detach X11 listener */
235519261079SEd Maste 		debug_f("detach x11 channel %d", id);
23564f52dfbbSDag-Erling Smørgrav 		channel_cancel_cleanup(ssh, id);
2357d4ecd108SDag-Erling Smørgrav 		if (c->ostate != CHAN_OUTPUT_CLOSED)
23584f52dfbbSDag-Erling Smørgrav 			chan_mark_dead(ssh, c);
2359d4ecd108SDag-Erling Smørgrav 	}
2360d4ecd108SDag-Erling Smørgrav }
2361d4ecd108SDag-Erling Smørgrav 
2362d4ecd108SDag-Erling Smørgrav static void
23634f52dfbbSDag-Erling Smørgrav session_close_single_x11(struct ssh *ssh, int id, void *arg)
2364d4ecd108SDag-Erling Smørgrav {
2365d4ecd108SDag-Erling Smørgrav 	Session *s;
2366d4ecd108SDag-Erling Smørgrav 	u_int i;
2367d4ecd108SDag-Erling Smørgrav 
236819261079SEd Maste 	debug3_f("channel %d", id);
23694f52dfbbSDag-Erling Smørgrav 	channel_cancel_cleanup(ssh, id);
2370d4ecd108SDag-Erling Smørgrav 	if ((s = session_by_x11_channel(id)) == NULL)
237119261079SEd Maste 		fatal_f("no x11 channel %d", id);
2372d4ecd108SDag-Erling Smørgrav 	for (i = 0; s->x11_chanids[i] != -1; i++) {
237319261079SEd Maste 		debug_f("session %d: closing channel %d",
237419261079SEd Maste 		    s->self, s->x11_chanids[i]);
2375d4ecd108SDag-Erling Smørgrav 		/*
2376d4ecd108SDag-Erling Smørgrav 		 * The channel "id" is already closing, but make sure we
2377d4ecd108SDag-Erling Smørgrav 		 * close all of its siblings.
2378d4ecd108SDag-Erling Smørgrav 		 */
2379d4ecd108SDag-Erling Smørgrav 		if (s->x11_chanids[i] != id)
23804f52dfbbSDag-Erling Smørgrav 			session_close_x11(ssh, s->x11_chanids[i]);
2381d4ecd108SDag-Erling Smørgrav 	}
2382e4a9863fSDag-Erling Smørgrav 	free(s->x11_chanids);
2383d4ecd108SDag-Erling Smørgrav 	s->x11_chanids = NULL;
2384e4a9863fSDag-Erling Smørgrav 	free(s->display);
2385d4ecd108SDag-Erling Smørgrav 	s->display = NULL;
2386e4a9863fSDag-Erling Smørgrav 	free(s->auth_proto);
2387d4ecd108SDag-Erling Smørgrav 	s->auth_proto = NULL;
2388e4a9863fSDag-Erling Smørgrav 	free(s->auth_data);
2389d4ecd108SDag-Erling Smørgrav 	s->auth_data = NULL;
2390e4a9863fSDag-Erling Smørgrav 	free(s->auth_display);
2391d4ecd108SDag-Erling Smørgrav 	s->auth_display = NULL;
2392d4ecd108SDag-Erling Smørgrav }
2393d4ecd108SDag-Erling Smørgrav 
2394d4ecd108SDag-Erling Smørgrav static void
23954f52dfbbSDag-Erling Smørgrav session_exit_message(struct ssh *ssh, Session *s, int status)
2396a04a10f8SKris Kennaway {
2397a04a10f8SKris Kennaway 	Channel *c;
239819261079SEd Maste 	int r;
2399af12a3e7SDag-Erling Smørgrav 
24004f52dfbbSDag-Erling Smørgrav 	if ((c = channel_lookup(ssh, s->chanid)) == NULL)
240119261079SEd Maste 		fatal_f("session %d: no channel %d", s->self, s->chanid);
240219261079SEd Maste 	debug_f("session %d channel %d pid %ld",
240319261079SEd Maste 	    s->self, s->chanid, (long)s->pid);
2404a04a10f8SKris Kennaway 
2405a04a10f8SKris Kennaway 	if (WIFEXITED(status)) {
24064f52dfbbSDag-Erling Smørgrav 		channel_request_start(ssh, s->chanid, "exit-status", 0);
240719261079SEd Maste 		if ((r = sshpkt_put_u32(ssh, WEXITSTATUS(status))) != 0 ||
240819261079SEd Maste 		    (r = sshpkt_send(ssh)) != 0)
240919261079SEd Maste 			sshpkt_fatal(ssh, r, "%s: exit reply", __func__);
2410a04a10f8SKris Kennaway 	} else if (WIFSIGNALED(status)) {
24114f52dfbbSDag-Erling Smørgrav 		channel_request_start(ssh, s->chanid, "exit-signal", 0);
241219261079SEd Maste #ifndef WCOREDUMP
241319261079SEd Maste # define WCOREDUMP(x) (0)
241419261079SEd Maste #endif
241519261079SEd Maste 		if ((r = sshpkt_put_cstring(ssh, sig2name(WTERMSIG(status)))) != 0 ||
241619261079SEd Maste 		    (r = sshpkt_put_u8(ssh, WCOREDUMP(status)? 1 : 0)) != 0 ||
241719261079SEd Maste 		    (r = sshpkt_put_cstring(ssh, "")) != 0 ||
241819261079SEd Maste 		    (r = sshpkt_put_cstring(ssh, "")) != 0 ||
241919261079SEd Maste 		    (r = sshpkt_send(ssh)) != 0)
242019261079SEd Maste 			sshpkt_fatal(ssh, r, "%s: exit reply", __func__);
2421a04a10f8SKris Kennaway 	} else {
2422a04a10f8SKris Kennaway 		/* Some weird exit cause.  Just exit. */
242319261079SEd Maste 		ssh_packet_disconnect(ssh, "wait returned status %04x.", status);
2424a04a10f8SKris Kennaway 	}
2425a04a10f8SKris Kennaway 
2426a04a10f8SKris Kennaway 	/* disconnect channel */
242719261079SEd Maste 	debug_f("release channel %d", s->chanid);
2428b74df5b2SDag-Erling Smørgrav 
2429b74df5b2SDag-Erling Smørgrav 	/*
2430b74df5b2SDag-Erling Smørgrav 	 * Adjust cleanup callback attachment to send close messages when
2431b74df5b2SDag-Erling Smørgrav 	 * the channel gets EOF. The session will be then be closed
243219261079SEd Maste 	 * by session_close_by_channel when the child sessions close their fds.
2433b74df5b2SDag-Erling Smørgrav 	 */
24344f52dfbbSDag-Erling Smørgrav 	channel_register_cleanup(ssh, c->self, session_close_by_channel, 1);
2435b74df5b2SDag-Erling Smørgrav 
2436a04a10f8SKris Kennaway 	/*
2437a04a10f8SKris Kennaway 	 * emulate a write failure with 'chan_write_failed', nobody will be
2438a04a10f8SKris Kennaway 	 * interested in data we write.
2439a04a10f8SKris Kennaway 	 * Note that we must not call 'chan_read_failed', since there could
2440a04a10f8SKris Kennaway 	 * be some more data waiting in the pipe.
2441a04a10f8SKris Kennaway 	 */
2442a04a10f8SKris Kennaway 	if (c->ostate != CHAN_OUTPUT_CLOSED)
24434f52dfbbSDag-Erling Smørgrav 		chan_write_failed(ssh, c);
2444a04a10f8SKris Kennaway }
2445a04a10f8SKris Kennaway 
244680628bacSDag-Erling Smørgrav void
24474f52dfbbSDag-Erling Smørgrav session_close(struct ssh *ssh, Session *s)
2448a04a10f8SKris Kennaway {
2449d4ecd108SDag-Erling Smørgrav 	u_int i;
245021e764dfSDag-Erling Smørgrav 
2451acc1a9efSDag-Erling Smørgrav 	verbose("Close session: user %s from %.200s port %d id %d",
2452acc1a9efSDag-Erling Smørgrav 	    s->pw->pw_name,
2453076ad2f8SDag-Erling Smørgrav 	    ssh_remote_ipaddr(ssh),
2454076ad2f8SDag-Erling Smørgrav 	    ssh_remote_port(ssh),
2455acc1a9efSDag-Erling Smørgrav 	    s->self);
2456acc1a9efSDag-Erling Smørgrav 
24571ec0d754SDag-Erling Smørgrav 	if (s->ttyfd != -1)
2458af12a3e7SDag-Erling Smørgrav 		session_pty_cleanup(s);
2459e4a9863fSDag-Erling Smørgrav 	free(s->term);
2460e4a9863fSDag-Erling Smørgrav 	free(s->display);
2461e4a9863fSDag-Erling Smørgrav 	free(s->x11_chanids);
2462e4a9863fSDag-Erling Smørgrav 	free(s->auth_display);
2463e4a9863fSDag-Erling Smørgrav 	free(s->auth_data);
2464e4a9863fSDag-Erling Smørgrav 	free(s->auth_proto);
2465f7167e0eSDag-Erling Smørgrav 	free(s->subsys);
2466333ee039SDag-Erling Smørgrav 	if (s->env != NULL) {
246721e764dfSDag-Erling Smørgrav 		for (i = 0; i < s->num_env; i++) {
2468e4a9863fSDag-Erling Smørgrav 			free(s->env[i].name);
2469e4a9863fSDag-Erling Smørgrav 			free(s->env[i].val);
247021e764dfSDag-Erling Smørgrav 		}
2471e4a9863fSDag-Erling Smørgrav 		free(s->env);
2472333ee039SDag-Erling Smørgrav 	}
2473a04a10f8SKris Kennaway 	session_proctitle(s);
2474d4af9e69SDag-Erling Smørgrav 	session_unused(s->self);
2475a04a10f8SKris Kennaway }
2476a04a10f8SKris Kennaway 
2477a04a10f8SKris Kennaway void
24784f52dfbbSDag-Erling Smørgrav session_close_by_pid(struct ssh *ssh, pid_t pid, int status)
2479a04a10f8SKris Kennaway {
2480a04a10f8SKris Kennaway 	Session *s = session_by_pid(pid);
2481a04a10f8SKris Kennaway 	if (s == NULL) {
248219261079SEd Maste 		debug_f("no session for pid %ld", (long)pid);
2483a04a10f8SKris Kennaway 		return;
2484a04a10f8SKris Kennaway 	}
2485a04a10f8SKris Kennaway 	if (s->chanid != -1)
24864f52dfbbSDag-Erling Smørgrav 		session_exit_message(ssh, s, status);
2487b74df5b2SDag-Erling Smørgrav 	if (s->ttyfd != -1)
2488b74df5b2SDag-Erling Smørgrav 		session_pty_cleanup(s);
2489333ee039SDag-Erling Smørgrav 	s->pid = 0;
2490a04a10f8SKris Kennaway }
2491a04a10f8SKris Kennaway 
2492a04a10f8SKris Kennaway /*
2493a04a10f8SKris Kennaway  * this is called when a channel dies before
2494a04a10f8SKris Kennaway  * the session 'child' itself dies
2495a04a10f8SKris Kennaway  */
2496a04a10f8SKris Kennaway void
24974f52dfbbSDag-Erling Smørgrav session_close_by_channel(struct ssh *ssh, int id, void *arg)
2498a04a10f8SKris Kennaway {
2499a04a10f8SKris Kennaway 	Session *s = session_by_channel(id);
2500b74df5b2SDag-Erling Smørgrav 	u_int i;
2501d4ecd108SDag-Erling Smørgrav 
2502a04a10f8SKris Kennaway 	if (s == NULL) {
250319261079SEd Maste 		debug_f("no session for id %d", id);
2504a04a10f8SKris Kennaway 		return;
2505a04a10f8SKris Kennaway 	}
250619261079SEd Maste 	debug_f("channel %d child %ld", id, (long)s->pid);
2507af12a3e7SDag-Erling Smørgrav 	if (s->pid != 0) {
250819261079SEd Maste 		debug_f("channel %d: has child, ttyfd %d", id, s->ttyfd);
2509af12a3e7SDag-Erling Smørgrav 		/*
2510af12a3e7SDag-Erling Smørgrav 		 * delay detach of session, but release pty, since
2511af12a3e7SDag-Erling Smørgrav 		 * the fd's to the child are already closed
2512af12a3e7SDag-Erling Smørgrav 		 */
25131ec0d754SDag-Erling Smørgrav 		if (s->ttyfd != -1)
2514af12a3e7SDag-Erling Smørgrav 			session_pty_cleanup(s);
2515af12a3e7SDag-Erling Smørgrav 		return;
2516af12a3e7SDag-Erling Smørgrav 	}
2517af12a3e7SDag-Erling Smørgrav 	/* detach by removing callback */
25184f52dfbbSDag-Erling Smørgrav 	channel_cancel_cleanup(ssh, s->chanid);
2519b74df5b2SDag-Erling Smørgrav 
2520b74df5b2SDag-Erling Smørgrav 	/* Close any X11 listeners associated with this session */
2521b74df5b2SDag-Erling Smørgrav 	if (s->x11_chanids != NULL) {
2522b74df5b2SDag-Erling Smørgrav 		for (i = 0; s->x11_chanids[i] != -1; i++) {
25234f52dfbbSDag-Erling Smørgrav 			session_close_x11(ssh, s->x11_chanids[i]);
2524b74df5b2SDag-Erling Smørgrav 			s->x11_chanids[i] = -1;
2525b74df5b2SDag-Erling Smørgrav 		}
2526b74df5b2SDag-Erling Smørgrav 	}
2527b74df5b2SDag-Erling Smørgrav 
2528a04a10f8SKris Kennaway 	s->chanid = -1;
25294f52dfbbSDag-Erling Smørgrav 	session_close(ssh, s);
2530af12a3e7SDag-Erling Smørgrav }
2531af12a3e7SDag-Erling Smørgrav 
2532af12a3e7SDag-Erling Smørgrav void
25334f52dfbbSDag-Erling Smørgrav session_destroy_all(struct ssh *ssh, void (*closefunc)(Session *))
2534af12a3e7SDag-Erling Smørgrav {
2535af12a3e7SDag-Erling Smørgrav 	int i;
2536d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
2537af12a3e7SDag-Erling Smørgrav 		Session *s = &sessions[i];
253880628bacSDag-Erling Smørgrav 		if (s->used) {
253980628bacSDag-Erling Smørgrav 			if (closefunc != NULL)
254080628bacSDag-Erling Smørgrav 				closefunc(s);
254180628bacSDag-Erling Smørgrav 			else
25424f52dfbbSDag-Erling Smørgrav 				session_close(ssh, s);
2543a04a10f8SKris Kennaway 		}
2544a04a10f8SKris Kennaway 	}
254580628bacSDag-Erling Smørgrav }
2546a04a10f8SKris Kennaway 
2547af12a3e7SDag-Erling Smørgrav static char *
2548a04a10f8SKris Kennaway session_tty_list(void)
2549a04a10f8SKris Kennaway {
2550a04a10f8SKris Kennaway 	static char buf[1024];
2551a04a10f8SKris Kennaway 	int i;
2552e73e9afaSDag-Erling Smørgrav 	char *cp;
2553e73e9afaSDag-Erling Smørgrav 
2554a04a10f8SKris Kennaway 	buf[0] = '\0';
2555d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
2556a04a10f8SKris Kennaway 		Session *s = &sessions[i];
2557a04a10f8SKris Kennaway 		if (s->used && s->ttyfd != -1) {
2558e73e9afaSDag-Erling Smørgrav 
2559e73e9afaSDag-Erling Smørgrav 			if (strncmp(s->tty, "/dev/", 5) != 0) {
2560e73e9afaSDag-Erling Smørgrav 				cp = strrchr(s->tty, '/');
2561e73e9afaSDag-Erling Smørgrav 				cp = (cp == NULL) ? s->tty : cp + 1;
2562e73e9afaSDag-Erling Smørgrav 			} else
2563e73e9afaSDag-Erling Smørgrav 				cp = s->tty + 5;
2564e73e9afaSDag-Erling Smørgrav 
2565a04a10f8SKris Kennaway 			if (buf[0] != '\0')
2566a04a10f8SKris Kennaway 				strlcat(buf, ",", sizeof buf);
2567e73e9afaSDag-Erling Smørgrav 			strlcat(buf, cp, sizeof buf);
2568a04a10f8SKris Kennaway 		}
2569a04a10f8SKris Kennaway 	}
2570a04a10f8SKris Kennaway 	if (buf[0] == '\0')
2571a04a10f8SKris Kennaway 		strlcpy(buf, "notty", sizeof buf);
2572a04a10f8SKris Kennaway 	return buf;
2573a04a10f8SKris Kennaway }
2574a04a10f8SKris Kennaway 
2575a04a10f8SKris Kennaway void
2576a04a10f8SKris Kennaway session_proctitle(Session *s)
2577a04a10f8SKris Kennaway {
2578a04a10f8SKris Kennaway 	if (s->pw == NULL)
2579a04a10f8SKris Kennaway 		error("no user for session %d", s->self);
2580a04a10f8SKris Kennaway 	else
2581a04a10f8SKris Kennaway 		setproctitle("%s@%s", s->pw->pw_name, session_tty_list());
2582a04a10f8SKris Kennaway }
2583a04a10f8SKris Kennaway 
2584af12a3e7SDag-Erling Smørgrav int
25854f52dfbbSDag-Erling Smørgrav session_setup_x11fwd(struct ssh *ssh, Session *s)
2586af12a3e7SDag-Erling Smørgrav {
2587af12a3e7SDag-Erling Smørgrav 	struct stat st;
2588af12a3e7SDag-Erling Smørgrav 	char display[512], auth_display[512];
2589a0ee8cc6SDag-Erling Smørgrav 	char hostname[NI_MAXHOST];
2590d4ecd108SDag-Erling Smørgrav 	u_int i;
2591af12a3e7SDag-Erling Smørgrav 
259247dd1d1bSDag-Erling Smørgrav 	if (!auth_opts->permit_x11_forwarding_flag) {
259319261079SEd Maste 		ssh_packet_send_debug(ssh, "X11 forwarding disabled by key options.");
2594af12a3e7SDag-Erling Smørgrav 		return 0;
2595af12a3e7SDag-Erling Smørgrav 	}
2596af12a3e7SDag-Erling Smørgrav 	if (!options.x11_forwarding) {
2597af12a3e7SDag-Erling Smørgrav 		debug("X11 forwarding disabled in server configuration file.");
2598af12a3e7SDag-Erling Smørgrav 		return 0;
2599af12a3e7SDag-Erling Smørgrav 	}
2600bc5531deSDag-Erling Smørgrav 	if (options.xauth_location == NULL ||
2601af12a3e7SDag-Erling Smørgrav 	    (stat(options.xauth_location, &st) == -1)) {
260219261079SEd Maste 		ssh_packet_send_debug(ssh, "No xauth program; cannot forward X11.");
2603af12a3e7SDag-Erling Smørgrav 		return 0;
2604af12a3e7SDag-Erling Smørgrav 	}
2605af12a3e7SDag-Erling Smørgrav 	if (s->display != NULL) {
2606af12a3e7SDag-Erling Smørgrav 		debug("X11 display already set.");
2607af12a3e7SDag-Erling Smørgrav 		return 0;
2608af12a3e7SDag-Erling Smørgrav 	}
26094f52dfbbSDag-Erling Smørgrav 	if (x11_create_display_inet(ssh, options.x11_display_offset,
2610a82e551fSDag-Erling Smørgrav 	    options.x11_use_localhost, s->single_connection,
2611d4ecd108SDag-Erling Smørgrav 	    &s->display_number, &s->x11_chanids) == -1) {
2612af12a3e7SDag-Erling Smørgrav 		debug("x11_create_display_inet failed.");
2613af12a3e7SDag-Erling Smørgrav 		return 0;
2614af12a3e7SDag-Erling Smørgrav 	}
2615d4ecd108SDag-Erling Smørgrav 	for (i = 0; s->x11_chanids[i] != -1; i++) {
26164f52dfbbSDag-Erling Smørgrav 		channel_register_cleanup(ssh, s->x11_chanids[i],
2617b74df5b2SDag-Erling Smørgrav 		    session_close_single_x11, 0);
2618d4ecd108SDag-Erling Smørgrav 	}
2619af12a3e7SDag-Erling Smørgrav 
2620af12a3e7SDag-Erling Smørgrav 	/* Set up a suitable value for the DISPLAY variable. */
262119261079SEd Maste 	if (gethostname(hostname, sizeof(hostname)) == -1)
2622af12a3e7SDag-Erling Smørgrav 		fatal("gethostname: %.100s", strerror(errno));
2623af12a3e7SDag-Erling Smørgrav 	/*
2624af12a3e7SDag-Erling Smørgrav 	 * auth_display must be used as the displayname when the
2625af12a3e7SDag-Erling Smørgrav 	 * authorization entry is added with xauth(1).  This will be
2626af12a3e7SDag-Erling Smørgrav 	 * different than the DISPLAY string for localhost displays.
2627af12a3e7SDag-Erling Smørgrav 	 */
2628af12a3e7SDag-Erling Smørgrav 	if (options.x11_use_localhost) {
2629a82e551fSDag-Erling Smørgrav 		snprintf(display, sizeof display, "localhost:%u.%u",
2630af12a3e7SDag-Erling Smørgrav 		    s->display_number, s->screen);
2631a82e551fSDag-Erling Smørgrav 		snprintf(auth_display, sizeof auth_display, "unix:%u.%u",
2632af12a3e7SDag-Erling Smørgrav 		    s->display_number, s->screen);
2633af12a3e7SDag-Erling Smørgrav 		s->display = xstrdup(display);
2634af12a3e7SDag-Erling Smørgrav 		s->auth_display = xstrdup(auth_display);
2635af12a3e7SDag-Erling Smørgrav 	} else {
2636989dd127SDag-Erling Smørgrav #ifdef IPADDR_IN_DISPLAY
2637989dd127SDag-Erling Smørgrav 		struct hostent *he;
2638989dd127SDag-Erling Smørgrav 		struct in_addr my_addr;
2639989dd127SDag-Erling Smørgrav 
2640989dd127SDag-Erling Smørgrav 		he = gethostbyname(hostname);
2641989dd127SDag-Erling Smørgrav 		if (he == NULL) {
2642989dd127SDag-Erling Smørgrav 			error("Can't get IP address for X11 DISPLAY.");
264319261079SEd Maste 			ssh_packet_send_debug(ssh, "Can't get IP address for X11 DISPLAY.");
2644989dd127SDag-Erling Smørgrav 			return 0;
2645989dd127SDag-Erling Smørgrav 		}
2646989dd127SDag-Erling Smørgrav 		memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr));
2647a82e551fSDag-Erling Smørgrav 		snprintf(display, sizeof display, "%.50s:%u.%u", inet_ntoa(my_addr),
2648989dd127SDag-Erling Smørgrav 		    s->display_number, s->screen);
2649989dd127SDag-Erling Smørgrav #else
2650a82e551fSDag-Erling Smørgrav 		snprintf(display, sizeof display, "%.400s:%u.%u", hostname,
2651af12a3e7SDag-Erling Smørgrav 		    s->display_number, s->screen);
2652989dd127SDag-Erling Smørgrav #endif
2653af12a3e7SDag-Erling Smørgrav 		s->display = xstrdup(display);
2654af12a3e7SDag-Erling Smørgrav 		s->auth_display = xstrdup(display);
2655af12a3e7SDag-Erling Smørgrav 	}
2656af12a3e7SDag-Erling Smørgrav 
2657af12a3e7SDag-Erling Smørgrav 	return 1;
2658af12a3e7SDag-Erling Smørgrav }
2659af12a3e7SDag-Erling Smørgrav 
2660af12a3e7SDag-Erling Smørgrav static void
26614f52dfbbSDag-Erling Smørgrav do_authenticated2(struct ssh *ssh, Authctxt *authctxt)
2662a04a10f8SKris Kennaway {
26634f52dfbbSDag-Erling Smørgrav 	server_loop2(ssh, authctxt);
26641ec0d754SDag-Erling Smørgrav }
26651ec0d754SDag-Erling Smørgrav 
26661ec0d754SDag-Erling Smørgrav void
26674f52dfbbSDag-Erling Smørgrav do_cleanup(struct ssh *ssh, Authctxt *authctxt)
26681ec0d754SDag-Erling Smørgrav {
26691ec0d754SDag-Erling Smørgrav 	static int called = 0;
26701ec0d754SDag-Erling Smørgrav 
26711ec0d754SDag-Erling Smørgrav 	debug("do_cleanup");
26721ec0d754SDag-Erling Smørgrav 
26731ec0d754SDag-Erling Smørgrav 	/* no cleanup if we're in the child for login shell */
26741ec0d754SDag-Erling Smørgrav 	if (is_child)
26751ec0d754SDag-Erling Smørgrav 		return;
26761ec0d754SDag-Erling Smørgrav 
26771ec0d754SDag-Erling Smørgrav 	/* avoid double cleanup */
26781ec0d754SDag-Erling Smørgrav 	if (called)
26791ec0d754SDag-Erling Smørgrav 		return;
26801ec0d754SDag-Erling Smørgrav 	called = 1;
26811ec0d754SDag-Erling Smørgrav 
2682d4af9e69SDag-Erling Smørgrav 	if (authctxt == NULL)
26831ec0d754SDag-Erling Smørgrav 		return;
2684d4af9e69SDag-Erling Smørgrav 
2685d4af9e69SDag-Erling Smørgrav #ifdef USE_PAM
2686d4af9e69SDag-Erling Smørgrav 	if (options.use_pam) {
2687d4af9e69SDag-Erling Smørgrav 		sshpam_cleanup();
2688d4af9e69SDag-Erling Smørgrav 		sshpam_thread_cleanup();
2689d4af9e69SDag-Erling Smørgrav 	}
2690d4af9e69SDag-Erling Smørgrav #endif
2691d4af9e69SDag-Erling Smørgrav 
2692d4af9e69SDag-Erling Smørgrav 	if (!authctxt->authenticated)
2693d4af9e69SDag-Erling Smørgrav 		return;
2694d4af9e69SDag-Erling Smørgrav 
26951ec0d754SDag-Erling Smørgrav #ifdef KRB5
26961ec0d754SDag-Erling Smørgrav 	if (options.kerberos_ticket_cleanup &&
26971ec0d754SDag-Erling Smørgrav 	    authctxt->krb5_ctx)
26981ec0d754SDag-Erling Smørgrav 		krb5_cleanup_proc(authctxt);
2699cf2b5f3bSDag-Erling Smørgrav #endif
27001ec0d754SDag-Erling Smørgrav 
27011ec0d754SDag-Erling Smørgrav #ifdef GSSAPI
2702ca86bcf2SDag-Erling Smørgrav 	if (options.gss_cleanup_creds)
27031ec0d754SDag-Erling Smørgrav 		ssh_gssapi_cleanup_creds();
27041ec0d754SDag-Erling Smørgrav #endif
27051ec0d754SDag-Erling Smørgrav 
27061ec0d754SDag-Erling Smørgrav 	/* remove agent socket */
27071ec0d754SDag-Erling Smørgrav 	auth_sock_cleanup_proc(authctxt->pw);
27081ec0d754SDag-Erling Smørgrav 
27094f52dfbbSDag-Erling Smørgrav 	/* remove userauth info */
27104f52dfbbSDag-Erling Smørgrav 	if (auth_info_file != NULL) {
27114f52dfbbSDag-Erling Smørgrav 		temporarily_use_uid(authctxt->pw);
27124f52dfbbSDag-Erling Smørgrav 		unlink(auth_info_file);
27134f52dfbbSDag-Erling Smørgrav 		restore_uid();
27144f52dfbbSDag-Erling Smørgrav 		free(auth_info_file);
27154f52dfbbSDag-Erling Smørgrav 		auth_info_file = NULL;
27164f52dfbbSDag-Erling Smørgrav 	}
27174f52dfbbSDag-Erling Smørgrav 
27181ec0d754SDag-Erling Smørgrav 	/*
27191ec0d754SDag-Erling Smørgrav 	 * Cleanup ptys/utmp only if privsep is disabled,
27201ec0d754SDag-Erling Smørgrav 	 * or if running in monitor.
27211ec0d754SDag-Erling Smørgrav 	 */
27221ec0d754SDag-Erling Smørgrav 	if (!use_privsep || mm_is_monitor())
27234f52dfbbSDag-Erling Smørgrav 		session_destroy_all(ssh, session_pty_cleanup2);
2724a04a10f8SKris Kennaway }
2725076ad2f8SDag-Erling Smørgrav 
2726076ad2f8SDag-Erling Smørgrav /* Return a name for the remote host that fits inside utmp_size */
2727076ad2f8SDag-Erling Smørgrav 
2728076ad2f8SDag-Erling Smørgrav const char *
2729076ad2f8SDag-Erling Smørgrav session_get_remote_name_or_ip(struct ssh *ssh, u_int utmp_size, int use_dns)
2730076ad2f8SDag-Erling Smørgrav {
2731076ad2f8SDag-Erling Smørgrav 	const char *remote = "";
2732076ad2f8SDag-Erling Smørgrav 
2733076ad2f8SDag-Erling Smørgrav 	if (utmp_size > 0)
2734076ad2f8SDag-Erling Smørgrav 		remote = auth_get_canonical_hostname(ssh, use_dns);
2735076ad2f8SDag-Erling Smørgrav 	if (utmp_size == 0 || strlen(remote) > utmp_size)
2736076ad2f8SDag-Erling Smørgrav 		remote = ssh_remote_ipaddr(ssh);
2737076ad2f8SDag-Erling Smørgrav 	return remote;
2738076ad2f8SDag-Erling Smørgrav }
2739076ad2f8SDag-Erling Smørgrav 
2740