xref: /freebsd/crypto/openssh/session.c (revision 6888a9be566d79246a948dcc4c0a914b1bee0c32)
1*6888a9beSDag-Erling Smørgrav /* $OpenBSD: session.c,v 1.261 2012/12/02 20:46:11 djm Exp $ */
289986192SBrooks Davis /* $FreeBSD$ */
3a04a10f8SKris Kennaway /*
4a04a10f8SKris Kennaway  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5a04a10f8SKris Kennaway  *                    All rights reserved
6c2d3a559SKris Kennaway  *
7c2d3a559SKris Kennaway  * As far as I am concerned, the code I have written for this software
8c2d3a559SKris Kennaway  * can be used freely for any purpose.  Any derived versions of this
9c2d3a559SKris Kennaway  * software must be clearly marked as such, and if the derived work is
10c2d3a559SKris Kennaway  * incompatible with the protocol description in the RFC file, it must be
11c2d3a559SKris Kennaway  * called by a name other than "ssh" or "Secure Shell".
12c2d3a559SKris Kennaway  *
13a04a10f8SKris Kennaway  * SSH2 support by Markus Friedl.
14af12a3e7SDag-Erling Smørgrav  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
15e8aafc91SKris Kennaway  *
16c2d3a559SKris Kennaway  * Redistribution and use in source and binary forms, with or without
17c2d3a559SKris Kennaway  * modification, are permitted provided that the following conditions
18c2d3a559SKris Kennaway  * are met:
19c2d3a559SKris Kennaway  * 1. Redistributions of source code must retain the above copyright
20c2d3a559SKris Kennaway  *    notice, this list of conditions and the following disclaimer.
21c2d3a559SKris Kennaway  * 2. Redistributions in binary form must reproduce the above copyright
22c2d3a559SKris Kennaway  *    notice, this list of conditions and the following disclaimer in the
23c2d3a559SKris Kennaway  *    documentation and/or other materials provided with the distribution.
24c2d3a559SKris Kennaway  *
25c2d3a559SKris Kennaway  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26c2d3a559SKris Kennaway  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27c2d3a559SKris Kennaway  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28c2d3a559SKris Kennaway  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29c2d3a559SKris Kennaway  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30c2d3a559SKris Kennaway  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31c2d3a559SKris Kennaway  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32c2d3a559SKris Kennaway  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33c2d3a559SKris Kennaway  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34c2d3a559SKris Kennaway  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35a04a10f8SKris Kennaway  */
36a04a10f8SKris Kennaway 
37a04a10f8SKris Kennaway #include "includes.h"
38333ee039SDag-Erling Smørgrav __RCSID("$FreeBSD$");
39a04a10f8SKris Kennaway 
40333ee039SDag-Erling Smørgrav #include <sys/types.h>
41333ee039SDag-Erling Smørgrav #include <sys/param.h>
42333ee039SDag-Erling Smørgrav #ifdef HAVE_SYS_STAT_H
43333ee039SDag-Erling Smørgrav # include <sys/stat.h>
44333ee039SDag-Erling Smørgrav #endif
45333ee039SDag-Erling Smørgrav #include <sys/socket.h>
46333ee039SDag-Erling Smørgrav #include <sys/un.h>
47333ee039SDag-Erling Smørgrav #include <sys/wait.h>
48333ee039SDag-Erling Smørgrav 
49333ee039SDag-Erling Smørgrav #include <arpa/inet.h>
50333ee039SDag-Erling Smørgrav 
51333ee039SDag-Erling Smørgrav #include <errno.h>
52e2f6069cSDag-Erling Smørgrav #include <fcntl.h>
53333ee039SDag-Erling Smørgrav #include <grp.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 <stdarg.h>
60333ee039SDag-Erling Smørgrav #include <stdio.h>
61333ee039SDag-Erling Smørgrav #include <stdlib.h>
62333ee039SDag-Erling Smørgrav #include <string.h>
63333ee039SDag-Erling Smørgrav #include <unistd.h>
64333ee039SDag-Erling Smørgrav 
65d4af9e69SDag-Erling Smørgrav #include "openbsd-compat/sys-queue.h"
66333ee039SDag-Erling Smørgrav #include "xmalloc.h"
67a04a10f8SKris Kennaway #include "ssh.h"
68ca3176e7SBrian Feldman #include "ssh1.h"
69ca3176e7SBrian Feldman #include "ssh2.h"
70ca3176e7SBrian Feldman #include "sshpty.h"
71a04a10f8SKris Kennaway #include "packet.h"
72a04a10f8SKris Kennaway #include "buffer.h"
7321e764dfSDag-Erling Smørgrav #include "match.h"
74a04a10f8SKris Kennaway #include "uidswap.h"
75a04a10f8SKris Kennaway #include "compat.h"
76a04a10f8SKris Kennaway #include "channels.h"
77333ee039SDag-Erling Smørgrav #include "key.h"
78333ee039SDag-Erling Smørgrav #include "cipher.h"
79333ee039SDag-Erling Smørgrav #ifdef GSSAPI
80333ee039SDag-Erling Smørgrav #include "ssh-gss.h"
81333ee039SDag-Erling Smørgrav #endif
82333ee039SDag-Erling Smørgrav #include "hostfile.h"
83a04a10f8SKris Kennaway #include "auth.h"
84c2d3a559SKris Kennaway #include "auth-options.h"
85ca3176e7SBrian Feldman #include "pathnames.h"
86ca3176e7SBrian Feldman #include "log.h"
87ca3176e7SBrian Feldman #include "servconf.h"
88ca3176e7SBrian Feldman #include "sshlogin.h"
89ca3176e7SBrian Feldman #include "serverloop.h"
90ca3176e7SBrian Feldman #include "canohost.h"
91d4af9e69SDag-Erling Smørgrav #include "misc.h"
92ca3176e7SBrian Feldman #include "session.h"
93d4ecd108SDag-Erling Smørgrav #include "kex.h"
9480628bacSDag-Erling Smørgrav #include "monitor_wrap.h"
95d4af9e69SDag-Erling Smørgrav #include "sftp.h"
96a04a10f8SKris Kennaway 
971ec0d754SDag-Erling Smørgrav #if defined(KRB5) && defined(USE_AFS)
981ec0d754SDag-Erling Smørgrav #include <kafs.h>
991ec0d754SDag-Erling Smørgrav #endif
1001ec0d754SDag-Erling Smørgrav 
101e146993eSDag-Erling Smørgrav #ifdef WITH_SELINUX
102e146993eSDag-Erling Smørgrav #include <selinux/selinux.h>
103e146993eSDag-Erling Smørgrav #endif
104e146993eSDag-Erling Smørgrav 
105cce7d346SDag-Erling Smørgrav #define IS_INTERNAL_SFTP(c) \
106cce7d346SDag-Erling Smørgrav 	(!strncmp(c, INTERNAL_SFTP_NAME, sizeof(INTERNAL_SFTP_NAME) - 1) && \
107cce7d346SDag-Erling Smørgrav 	 (c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\0' || \
108cce7d346SDag-Erling Smørgrav 	  c[sizeof(INTERNAL_SFTP_NAME) - 1] == ' ' || \
109cce7d346SDag-Erling Smørgrav 	  c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\t'))
110cce7d346SDag-Erling Smørgrav 
111a04a10f8SKris Kennaway /* func */
112a04a10f8SKris Kennaway 
113a04a10f8SKris Kennaway Session *session_new(void);
114e2f6069cSDag-Erling Smørgrav void	session_set_fds(Session *, int, int, int, int, int);
1151ec0d754SDag-Erling Smørgrav void	session_pty_cleanup(Session *);
116af12a3e7SDag-Erling Smørgrav void	session_proctitle(Session *);
117af12a3e7SDag-Erling Smørgrav int	session_setup_x11fwd(Session *);
118d4af9e69SDag-Erling Smørgrav int	do_exec_pty(Session *, const char *);
119d4af9e69SDag-Erling Smørgrav int	do_exec_no_pty(Session *, const char *);
120d4af9e69SDag-Erling Smørgrav int	do_exec(Session *, const char *);
121af12a3e7SDag-Erling Smørgrav void	do_login(Session *, const char *);
122989dd127SDag-Erling Smørgrav #ifdef LOGIN_NEEDS_UTMPX
123989dd127SDag-Erling Smørgrav static void	do_pre_login(Session *s);
124989dd127SDag-Erling Smørgrav #endif
125af12a3e7SDag-Erling Smørgrav void	do_child(Session *, const char *);
126ca3176e7SBrian Feldman void	do_motd(void);
127af12a3e7SDag-Erling Smørgrav int	check_quietlogin(Session *, const char *);
128a04a10f8SKris Kennaway 
129af12a3e7SDag-Erling Smørgrav static void do_authenticated1(Authctxt *);
130af12a3e7SDag-Erling Smørgrav static void do_authenticated2(Authctxt *);
131af12a3e7SDag-Erling Smørgrav 
132af12a3e7SDag-Erling Smørgrav static int session_pty_req(Session *);
133a04a10f8SKris Kennaway 
134a04a10f8SKris Kennaway /* import */
135a04a10f8SKris Kennaway extern ServerOptions options;
136a04a10f8SKris Kennaway extern char *__progname;
137a04a10f8SKris Kennaway extern int log_stderr;
138a04a10f8SKris Kennaway extern int debug_flag;
139ca3176e7SBrian Feldman extern u_int utmp_len;
140c2d3a559SKris Kennaway extern int startup_pipe;
141ca3176e7SBrian Feldman extern void destroy_sensitive_data(void);
142cf2b5f3bSDag-Erling Smørgrav extern Buffer loginmsg;
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;
1621ec0d754SDag-Erling Smørgrav 
16380628bacSDag-Erling Smørgrav /* Name and directory of socket for authentication agent forwarding. */
16480628bacSDag-Erling Smørgrav static char *auth_sock_name = NULL;
16580628bacSDag-Erling Smørgrav static char *auth_sock_dir = NULL;
16680628bacSDag-Erling Smørgrav 
16780628bacSDag-Erling Smørgrav /* removes the agent forwarding socket */
16880628bacSDag-Erling Smørgrav 
16980628bacSDag-Erling Smørgrav static void
1701ec0d754SDag-Erling Smørgrav auth_sock_cleanup_proc(struct passwd *pw)
17180628bacSDag-Erling Smørgrav {
17280628bacSDag-Erling Smørgrav 	if (auth_sock_name != NULL) {
17380628bacSDag-Erling Smørgrav 		temporarily_use_uid(pw);
17480628bacSDag-Erling Smørgrav 		unlink(auth_sock_name);
17580628bacSDag-Erling Smørgrav 		rmdir(auth_sock_dir);
17680628bacSDag-Erling Smørgrav 		auth_sock_name = NULL;
17780628bacSDag-Erling Smørgrav 		restore_uid();
17880628bacSDag-Erling Smørgrav 	}
17980628bacSDag-Erling Smørgrav }
18080628bacSDag-Erling Smørgrav 
18180628bacSDag-Erling Smørgrav static int
18280628bacSDag-Erling Smørgrav auth_input_request_forwarding(struct passwd * pw)
18380628bacSDag-Erling Smørgrav {
18480628bacSDag-Erling Smørgrav 	Channel *nc;
185d4af9e69SDag-Erling Smørgrav 	int sock = -1;
18680628bacSDag-Erling Smørgrav 	struct sockaddr_un sunaddr;
18780628bacSDag-Erling Smørgrav 
18880628bacSDag-Erling Smørgrav 	if (auth_sock_name != NULL) {
18980628bacSDag-Erling Smørgrav 		error("authentication forwarding requested twice.");
19080628bacSDag-Erling Smørgrav 		return 0;
19180628bacSDag-Erling Smørgrav 	}
19280628bacSDag-Erling Smørgrav 
19380628bacSDag-Erling Smørgrav 	/* Temporarily drop privileged uid for mkdir/bind. */
19480628bacSDag-Erling Smørgrav 	temporarily_use_uid(pw);
19580628bacSDag-Erling Smørgrav 
19680628bacSDag-Erling Smørgrav 	/* Allocate a buffer for the socket name, and format the name. */
197d4af9e69SDag-Erling Smørgrav 	auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX");
19880628bacSDag-Erling Smørgrav 
19980628bacSDag-Erling Smørgrav 	/* Create private directory for socket */
20080628bacSDag-Erling Smørgrav 	if (mkdtemp(auth_sock_dir) == NULL) {
20180628bacSDag-Erling Smørgrav 		packet_send_debug("Agent forwarding disabled: "
20280628bacSDag-Erling Smørgrav 		    "mkdtemp() failed: %.100s", strerror(errno));
20380628bacSDag-Erling Smørgrav 		restore_uid();
20480628bacSDag-Erling Smørgrav 		xfree(auth_sock_dir);
20580628bacSDag-Erling Smørgrav 		auth_sock_dir = NULL;
206d4af9e69SDag-Erling Smørgrav 		goto authsock_err;
20780628bacSDag-Erling Smørgrav 	}
208d4af9e69SDag-Erling Smørgrav 
209d4af9e69SDag-Erling Smørgrav 	xasprintf(&auth_sock_name, "%s/agent.%ld",
21080628bacSDag-Erling Smørgrav 	    auth_sock_dir, (long) getpid());
21180628bacSDag-Erling Smørgrav 
21280628bacSDag-Erling Smørgrav 	/* Create the socket. */
21380628bacSDag-Erling Smørgrav 	sock = socket(AF_UNIX, SOCK_STREAM, 0);
214d4af9e69SDag-Erling Smørgrav 	if (sock < 0) {
215d4af9e69SDag-Erling Smørgrav 		error("socket: %.100s", strerror(errno));
216d4af9e69SDag-Erling Smørgrav 		restore_uid();
217d4af9e69SDag-Erling Smørgrav 		goto authsock_err;
218d4af9e69SDag-Erling Smørgrav 	}
21980628bacSDag-Erling Smørgrav 
22080628bacSDag-Erling Smørgrav 	/* Bind it to the name. */
22180628bacSDag-Erling Smørgrav 	memset(&sunaddr, 0, sizeof(sunaddr));
22280628bacSDag-Erling Smørgrav 	sunaddr.sun_family = AF_UNIX;
22380628bacSDag-Erling Smørgrav 	strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path));
22480628bacSDag-Erling Smørgrav 
225d4af9e69SDag-Erling Smørgrav 	if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
226d4af9e69SDag-Erling Smørgrav 		error("bind: %.100s", strerror(errno));
227d4af9e69SDag-Erling Smørgrav 		restore_uid();
228d4af9e69SDag-Erling Smørgrav 		goto authsock_err;
229d4af9e69SDag-Erling Smørgrav 	}
23080628bacSDag-Erling Smørgrav 
23180628bacSDag-Erling Smørgrav 	/* Restore the privileged uid. */
23280628bacSDag-Erling Smørgrav 	restore_uid();
23380628bacSDag-Erling Smørgrav 
23480628bacSDag-Erling Smørgrav 	/* Start listening on the socket. */
235d4af9e69SDag-Erling Smørgrav 	if (listen(sock, SSH_LISTEN_BACKLOG) < 0) {
236d4af9e69SDag-Erling Smørgrav 		error("listen: %.100s", strerror(errno));
237d4af9e69SDag-Erling Smørgrav 		goto authsock_err;
238d4af9e69SDag-Erling Smørgrav 	}
23980628bacSDag-Erling Smørgrav 
24089986192SBrooks Davis 	/*
24189986192SBrooks Davis 	 * Allocate a channel for the authentication agent socket.
24289986192SBrooks Davis 	 * Ignore HPN on that one given no improvement expected.
24389986192SBrooks Davis 	 */
24480628bacSDag-Erling Smørgrav 	nc = channel_new("auth socket",
24580628bacSDag-Erling Smørgrav 	    SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,
24680628bacSDag-Erling Smørgrav 	    CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
247cf2b5f3bSDag-Erling Smørgrav 	    0, "auth socket", 1);
248cce7d346SDag-Erling Smørgrav 	nc->path = xstrdup(auth_sock_name);
24980628bacSDag-Erling Smørgrav 	return 1;
250d4af9e69SDag-Erling Smørgrav 
251d4af9e69SDag-Erling Smørgrav  authsock_err:
252d4af9e69SDag-Erling Smørgrav 	if (auth_sock_name != NULL)
253d4af9e69SDag-Erling Smørgrav 		xfree(auth_sock_name);
254d4af9e69SDag-Erling Smørgrav 	if (auth_sock_dir != NULL) {
255d4af9e69SDag-Erling Smørgrav 		rmdir(auth_sock_dir);
256d4af9e69SDag-Erling Smørgrav 		xfree(auth_sock_dir);
257d4af9e69SDag-Erling Smørgrav 	}
258d4af9e69SDag-Erling Smørgrav 	if (sock != -1)
259d4af9e69SDag-Erling Smørgrav 		close(sock);
260d4af9e69SDag-Erling Smørgrav 	auth_sock_name = NULL;
261d4af9e69SDag-Erling Smørgrav 	auth_sock_dir = NULL;
262d4af9e69SDag-Erling Smørgrav 	return 0;
26380628bacSDag-Erling Smørgrav }
26480628bacSDag-Erling Smørgrav 
2651ec0d754SDag-Erling Smørgrav static void
2661ec0d754SDag-Erling Smørgrav display_loginmsg(void)
2671ec0d754SDag-Erling Smørgrav {
2681ec0d754SDag-Erling Smørgrav 	if (buffer_len(&loginmsg) > 0) {
2691ec0d754SDag-Erling Smørgrav 		buffer_append(&loginmsg, "\0", 1);
27021e764dfSDag-Erling Smørgrav 		printf("%s", (char *)buffer_ptr(&loginmsg));
2711ec0d754SDag-Erling Smørgrav 		buffer_clear(&loginmsg);
2721ec0d754SDag-Erling Smørgrav 	}
2731ec0d754SDag-Erling Smørgrav }
27480628bacSDag-Erling Smørgrav 
275ca3176e7SBrian Feldman void
276ca3176e7SBrian Feldman do_authenticated(Authctxt *authctxt)
277ca3176e7SBrian Feldman {
278e73e9afaSDag-Erling Smørgrav 	setproctitle("%s", authctxt->pw->pw_name);
279e73e9afaSDag-Erling Smørgrav 
280ca3176e7SBrian Feldman 	/* setup the channel layer */
281*6888a9beSDag-Erling Smørgrav 	if (no_port_forwarding_flag ||
282*6888a9beSDag-Erling Smørgrav 	    (options.allow_tcp_forwarding & FORWARD_LOCAL) == 0)
283*6888a9beSDag-Erling Smørgrav 		channel_disable_adm_local_opens();
284*6888a9beSDag-Erling Smørgrav 	else
285ca3176e7SBrian Feldman 		channel_permit_all_opens();
286ca3176e7SBrian Feldman 
287b15c8340SDag-Erling Smørgrav 	auth_debug_send();
288b15c8340SDag-Erling Smørgrav 
289ca3176e7SBrian Feldman 	if (compat20)
290ca3176e7SBrian Feldman 		do_authenticated2(authctxt);
291ca3176e7SBrian Feldman 	else
292ca3176e7SBrian Feldman 		do_authenticated1(authctxt);
293e9fd63dfSBrian Feldman 
2941ec0d754SDag-Erling Smørgrav 	do_cleanup(authctxt);
295a04a10f8SKris Kennaway }
296a04a10f8SKris Kennaway 
297a04a10f8SKris Kennaway /*
298a04a10f8SKris Kennaway  * Prepares for an interactive session.  This is called after the user has
299a04a10f8SKris Kennaway  * been successfully authenticated.  During this message exchange, pseudo
300a04a10f8SKris Kennaway  * terminals are allocated, X11, TCP/IP, and authentication agent forwardings
301a04a10f8SKris Kennaway  * are requested, etc.
302a04a10f8SKris Kennaway  */
303af12a3e7SDag-Erling Smørgrav static void
304ca3176e7SBrian Feldman do_authenticated1(Authctxt *authctxt)
305a04a10f8SKris Kennaway {
306a04a10f8SKris Kennaway 	Session *s;
307a04a10f8SKris Kennaway 	char *command;
308af12a3e7SDag-Erling Smørgrav 	int success, type, screen_flag;
309a82e551fSDag-Erling Smørgrav 	int enable_compression_after_reply = 0;
310a82e551fSDag-Erling Smørgrav 	u_int proto_len, data_len, dlen, compression_level = 0;
311a04a10f8SKris Kennaway 
312a04a10f8SKris Kennaway 	s = session_new();
313aa49c926SDag-Erling Smørgrav 	if (s == NULL) {
314aa49c926SDag-Erling Smørgrav 		error("no more sessions");
315aa49c926SDag-Erling Smørgrav 		return;
316aa49c926SDag-Erling Smørgrav 	}
317af12a3e7SDag-Erling Smørgrav 	s->authctxt = authctxt;
318ca3176e7SBrian Feldman 	s->pw = authctxt->pw;
319c2d3a559SKris Kennaway 
320a04a10f8SKris Kennaway 	/*
321a04a10f8SKris Kennaway 	 * We stay in this loop until the client requests to execute a shell
322a04a10f8SKris Kennaway 	 * or a command.
323a04a10f8SKris Kennaway 	 */
324a04a10f8SKris Kennaway 	for (;;) {
325ca3176e7SBrian Feldman 		success = 0;
326a04a10f8SKris Kennaway 
327a04a10f8SKris Kennaway 		/* Get a packet from the client. */
328af12a3e7SDag-Erling Smørgrav 		type = packet_read();
329a04a10f8SKris Kennaway 
330a04a10f8SKris Kennaway 		/* Process the packet. */
331a04a10f8SKris Kennaway 		switch (type) {
332a04a10f8SKris Kennaway 		case SSH_CMSG_REQUEST_COMPRESSION:
333a04a10f8SKris Kennaway 			compression_level = packet_get_int();
334af12a3e7SDag-Erling Smørgrav 			packet_check_eom();
335a04a10f8SKris Kennaway 			if (compression_level < 1 || compression_level > 9) {
33621e764dfSDag-Erling Smørgrav 				packet_send_debug("Received invalid compression level %d.",
337a04a10f8SKris Kennaway 				    compression_level);
338a04a10f8SKris Kennaway 				break;
339a04a10f8SKris Kennaway 			}
340d4ecd108SDag-Erling Smørgrav 			if (options.compression == COMP_NONE) {
34180628bacSDag-Erling Smørgrav 				debug2("compression disabled");
34280628bacSDag-Erling Smørgrav 				break;
34380628bacSDag-Erling Smørgrav 			}
344a04a10f8SKris Kennaway 			/* Enable compression after we have responded with SUCCESS. */
345a04a10f8SKris Kennaway 			enable_compression_after_reply = 1;
346a04a10f8SKris Kennaway 			success = 1;
347a04a10f8SKris Kennaway 			break;
348a04a10f8SKris Kennaway 
349a04a10f8SKris Kennaway 		case SSH_CMSG_REQUEST_PTY:
350af12a3e7SDag-Erling Smørgrav 			success = session_pty_req(s);
351a04a10f8SKris Kennaway 			break;
352a04a10f8SKris Kennaway 
353a04a10f8SKris Kennaway 		case SSH_CMSG_X11_REQUEST_FORWARDING:
354a04a10f8SKris Kennaway 			s->auth_proto = packet_get_string(&proto_len);
355a04a10f8SKris Kennaway 			s->auth_data = packet_get_string(&data_len);
356a04a10f8SKris Kennaway 
357ca3176e7SBrian Feldman 			screen_flag = packet_get_protocol_flags() &
358ca3176e7SBrian Feldman 			    SSH_PROTOFLAG_SCREEN_NUMBER;
359ca3176e7SBrian Feldman 			debug2("SSH_PROTOFLAG_SCREEN_NUMBER: %d", screen_flag);
360ca3176e7SBrian Feldman 
361ca3176e7SBrian Feldman 			if (packet_remaining() == 4) {
362ca3176e7SBrian Feldman 				if (!screen_flag)
363ca3176e7SBrian Feldman 					debug2("Buggy client: "
364ca3176e7SBrian Feldman 					    "X11 screen flag missing");
365a04a10f8SKris Kennaway 				s->screen = packet_get_int();
366ca3176e7SBrian Feldman 			} else {
367a04a10f8SKris Kennaway 				s->screen = 0;
368ca3176e7SBrian Feldman 			}
369af12a3e7SDag-Erling Smørgrav 			packet_check_eom();
370af12a3e7SDag-Erling Smørgrav 			success = session_setup_x11fwd(s);
371af12a3e7SDag-Erling Smørgrav 			if (!success) {
372af12a3e7SDag-Erling Smørgrav 				xfree(s->auth_proto);
373af12a3e7SDag-Erling Smørgrav 				xfree(s->auth_data);
374af12a3e7SDag-Erling Smørgrav 				s->auth_proto = NULL;
375af12a3e7SDag-Erling Smørgrav 				s->auth_data = NULL;
376a04a10f8SKris Kennaway 			}
377a04a10f8SKris Kennaway 			break;
378a04a10f8SKris Kennaway 
379a04a10f8SKris Kennaway 		case SSH_CMSG_AGENT_REQUEST_FORWARDING:
380d4af9e69SDag-Erling Smørgrav 			if (!options.allow_agent_forwarding ||
381d4af9e69SDag-Erling Smørgrav 			    no_agent_forwarding_flag || compat13) {
382a04a10f8SKris Kennaway 				debug("Authentication agent forwarding not permitted for this authentication.");
383a04a10f8SKris Kennaway 				break;
384a04a10f8SKris Kennaway 			}
385a04a10f8SKris Kennaway 			debug("Received authentication agent forwarding request.");
386ca3176e7SBrian Feldman 			success = auth_input_request_forwarding(s->pw);
387a04a10f8SKris Kennaway 			break;
388a04a10f8SKris Kennaway 
389a04a10f8SKris Kennaway 		case SSH_CMSG_PORT_FORWARD_REQUEST:
390a04a10f8SKris Kennaway 			if (no_port_forwarding_flag) {
391a04a10f8SKris Kennaway 				debug("Port forwarding not permitted for this authentication.");
392a04a10f8SKris Kennaway 				break;
393a04a10f8SKris Kennaway 			}
394*6888a9beSDag-Erling Smørgrav 			if (!(options.allow_tcp_forwarding & FORWARD_REMOTE)) {
39509958426SBrian Feldman 				debug("Port forwarding not permitted.");
39609958426SBrian Feldman 				break;
39709958426SBrian Feldman 			}
398a04a10f8SKris Kennaway 			debug("Received TCP/IP port forwarding request.");
399333ee039SDag-Erling Smørgrav 			if (channel_input_port_forward_request(s->pw->pw_uid == 0,
400333ee039SDag-Erling Smørgrav 			    options.gateway_ports) < 0) {
401333ee039SDag-Erling Smørgrav 				debug("Port forwarding failed.");
402333ee039SDag-Erling Smørgrav 				break;
403333ee039SDag-Erling Smørgrav 			}
404a04a10f8SKris Kennaway 			success = 1;
405a04a10f8SKris Kennaway 			break;
406a04a10f8SKris Kennaway 
407a04a10f8SKris Kennaway 		case SSH_CMSG_MAX_PACKET_SIZE:
408a04a10f8SKris Kennaway 			if (packet_set_maxsize(packet_get_int()) > 0)
409a04a10f8SKris Kennaway 				success = 1;
410a04a10f8SKris Kennaway 			break;
411a04a10f8SKris Kennaway 
412a04a10f8SKris Kennaway 		case SSH_CMSG_EXEC_SHELL:
413a04a10f8SKris Kennaway 		case SSH_CMSG_EXEC_CMD:
414a04a10f8SKris Kennaway 			if (type == SSH_CMSG_EXEC_CMD) {
415a04a10f8SKris Kennaway 				command = packet_get_string(&dlen);
416a04a10f8SKris Kennaway 				debug("Exec command '%.500s'", command);
417d4af9e69SDag-Erling Smørgrav 				if (do_exec(s, command) != 0)
418d4af9e69SDag-Erling Smørgrav 					packet_disconnect(
419d4af9e69SDag-Erling Smørgrav 					    "command execution failed");
420a04a10f8SKris Kennaway 				xfree(command);
421af12a3e7SDag-Erling Smørgrav 			} else {
422d4af9e69SDag-Erling Smørgrav 				if (do_exec(s, NULL) != 0)
423d4af9e69SDag-Erling Smørgrav 					packet_disconnect(
424d4af9e69SDag-Erling Smørgrav 					    "shell execution failed");
425af12a3e7SDag-Erling Smørgrav 			}
426af12a3e7SDag-Erling Smørgrav 			packet_check_eom();
427af12a3e7SDag-Erling Smørgrav 			session_close(s);
428a04a10f8SKris Kennaway 			return;
429a04a10f8SKris Kennaway 
430a04a10f8SKris Kennaway 		default:
431a04a10f8SKris Kennaway 			/*
432a04a10f8SKris Kennaway 			 * Any unknown messages in this phase are ignored,
433a04a10f8SKris Kennaway 			 * and a failure message is returned.
434a04a10f8SKris Kennaway 			 */
435cf2b5f3bSDag-Erling Smørgrav 			logit("Unknown packet type received after authentication: %d", type);
436a04a10f8SKris Kennaway 		}
437a04a10f8SKris Kennaway 		packet_start(success ? SSH_SMSG_SUCCESS : SSH_SMSG_FAILURE);
438a04a10f8SKris Kennaway 		packet_send();
439a04a10f8SKris Kennaway 		packet_write_wait();
440a04a10f8SKris Kennaway 
441a04a10f8SKris Kennaway 		/* Enable compression now that we have replied if appropriate. */
442a04a10f8SKris Kennaway 		if (enable_compression_after_reply) {
443a04a10f8SKris Kennaway 			enable_compression_after_reply = 0;
444a04a10f8SKris Kennaway 			packet_start_compression(compression_level);
445a04a10f8SKris Kennaway 		}
446a04a10f8SKris Kennaway 	}
447a04a10f8SKris Kennaway }
448a04a10f8SKris Kennaway 
449d4af9e69SDag-Erling Smørgrav #define USE_PIPES
450a04a10f8SKris Kennaway /*
451a04a10f8SKris Kennaway  * This is called to fork and execute a command when we have no tty.  This
452a04a10f8SKris Kennaway  * will call do_child from the child, and server_loop from the parent after
453a04a10f8SKris Kennaway  * setting up file descriptors and such.
454a04a10f8SKris Kennaway  */
455d4af9e69SDag-Erling Smørgrav int
456ca3176e7SBrian Feldman do_exec_no_pty(Session *s, const char *command)
457a04a10f8SKris Kennaway {
45880628bacSDag-Erling Smørgrav 	pid_t pid;
459a04a10f8SKris Kennaway 
460a04a10f8SKris Kennaway #ifdef USE_PIPES
461a04a10f8SKris Kennaway 	int pin[2], pout[2], perr[2];
462d4af9e69SDag-Erling Smørgrav 
463e2f6069cSDag-Erling Smørgrav 	if (s == NULL)
464e2f6069cSDag-Erling Smørgrav 		fatal("do_exec_no_pty: no session");
465e2f6069cSDag-Erling Smørgrav 
466a04a10f8SKris Kennaway 	/* Allocate pipes for communicating with the program. */
467d4af9e69SDag-Erling Smørgrav 	if (pipe(pin) < 0) {
468d4af9e69SDag-Erling Smørgrav 		error("%s: pipe in: %.100s", __func__, strerror(errno));
469d4af9e69SDag-Erling Smørgrav 		return -1;
470d4af9e69SDag-Erling Smørgrav 	}
471d4af9e69SDag-Erling Smørgrav 	if (pipe(pout) < 0) {
472d4af9e69SDag-Erling Smørgrav 		error("%s: pipe out: %.100s", __func__, strerror(errno));
473d4af9e69SDag-Erling Smørgrav 		close(pin[0]);
474d4af9e69SDag-Erling Smørgrav 		close(pin[1]);
475d4af9e69SDag-Erling Smørgrav 		return -1;
476d4af9e69SDag-Erling Smørgrav 	}
477d4af9e69SDag-Erling Smørgrav 	if (pipe(perr) < 0) {
478e2f6069cSDag-Erling Smørgrav 		error("%s: pipe err: %.100s", __func__,
479e2f6069cSDag-Erling Smørgrav 		    strerror(errno));
480d4af9e69SDag-Erling Smørgrav 		close(pin[0]);
481d4af9e69SDag-Erling Smørgrav 		close(pin[1]);
482d4af9e69SDag-Erling Smørgrav 		close(pout[0]);
483d4af9e69SDag-Erling Smørgrav 		close(pout[1]);
484d4af9e69SDag-Erling Smørgrav 		return -1;
485d4af9e69SDag-Erling Smørgrav 	}
486d4af9e69SDag-Erling Smørgrav #else
487a04a10f8SKris Kennaway 	int inout[2], err[2];
488d4af9e69SDag-Erling Smørgrav 
489e2f6069cSDag-Erling Smørgrav 	if (s == NULL)
490e2f6069cSDag-Erling Smørgrav 		fatal("do_exec_no_pty: no session");
491e2f6069cSDag-Erling Smørgrav 
492a04a10f8SKris Kennaway 	/* Uses socket pairs to communicate with the program. */
493d4af9e69SDag-Erling Smørgrav 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0) {
494d4af9e69SDag-Erling Smørgrav 		error("%s: socketpair #1: %.100s", __func__, strerror(errno));
495d4af9e69SDag-Erling Smørgrav 		return -1;
496d4af9e69SDag-Erling Smørgrav 	}
497d4af9e69SDag-Erling Smørgrav 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) {
498e2f6069cSDag-Erling Smørgrav 		error("%s: socketpair #2: %.100s", __func__,
499e2f6069cSDag-Erling Smørgrav 		    strerror(errno));
500d4af9e69SDag-Erling Smørgrav 		close(inout[0]);
501d4af9e69SDag-Erling Smørgrav 		close(inout[1]);
502d4af9e69SDag-Erling Smørgrav 		return -1;
503d4af9e69SDag-Erling Smørgrav 	}
504d4af9e69SDag-Erling Smørgrav #endif
505d4af9e69SDag-Erling Smørgrav 
506a04a10f8SKris Kennaway 	session_proctitle(s);
507a04a10f8SKris Kennaway 
508a04a10f8SKris Kennaway 	/* Fork the child. */
509d4af9e69SDag-Erling Smørgrav 	switch ((pid = fork())) {
510d4af9e69SDag-Erling Smørgrav 	case -1:
511d4af9e69SDag-Erling Smørgrav 		error("%s: fork: %.100s", __func__, strerror(errno));
512d4af9e69SDag-Erling Smørgrav #ifdef USE_PIPES
513d4af9e69SDag-Erling Smørgrav 		close(pin[0]);
514d4af9e69SDag-Erling Smørgrav 		close(pin[1]);
515d4af9e69SDag-Erling Smørgrav 		close(pout[0]);
516d4af9e69SDag-Erling Smørgrav 		close(pout[1]);
517d4af9e69SDag-Erling Smørgrav 		close(perr[0]);
518d4af9e69SDag-Erling Smørgrav 		close(perr[1]);
519d4af9e69SDag-Erling Smørgrav #else
520d4af9e69SDag-Erling Smørgrav 		close(inout[0]);
521d4af9e69SDag-Erling Smørgrav 		close(inout[1]);
522d4af9e69SDag-Erling Smørgrav 		close(err[0]);
523d4af9e69SDag-Erling Smørgrav 		close(err[1]);
524d4af9e69SDag-Erling Smørgrav #endif
525d4af9e69SDag-Erling Smørgrav 		return -1;
526d4af9e69SDag-Erling Smørgrav 	case 0:
5271ec0d754SDag-Erling Smørgrav 		is_child = 1;
528f388f5efSDag-Erling Smørgrav 
529a04a10f8SKris Kennaway 		/* Child.  Reinitialize the log since the pid has changed. */
530d4af9e69SDag-Erling Smørgrav 		log_init(__progname, options.log_level,
531d4af9e69SDag-Erling Smørgrav 		    options.log_facility, log_stderr);
532a04a10f8SKris Kennaway 
533a04a10f8SKris Kennaway 		/*
534a04a10f8SKris Kennaway 		 * Create a new session and process group since the 4.4BSD
535a04a10f8SKris Kennaway 		 * setlogin() affects the entire process group.
536a04a10f8SKris Kennaway 		 */
537a04a10f8SKris Kennaway 		if (setsid() < 0)
538a04a10f8SKris Kennaway 			error("setsid failed: %.100s", strerror(errno));
539a04a10f8SKris Kennaway 
540a04a10f8SKris Kennaway #ifdef USE_PIPES
541a04a10f8SKris Kennaway 		/*
542a04a10f8SKris Kennaway 		 * Redirect stdin.  We close the parent side of the socket
543a04a10f8SKris Kennaway 		 * pair, and make the child side the standard input.
544a04a10f8SKris Kennaway 		 */
545a04a10f8SKris Kennaway 		close(pin[1]);
546a04a10f8SKris Kennaway 		if (dup2(pin[0], 0) < 0)
547a04a10f8SKris Kennaway 			perror("dup2 stdin");
548a04a10f8SKris Kennaway 		close(pin[0]);
549a04a10f8SKris Kennaway 
550a04a10f8SKris Kennaway 		/* Redirect stdout. */
551a04a10f8SKris Kennaway 		close(pout[0]);
552a04a10f8SKris Kennaway 		if (dup2(pout[1], 1) < 0)
553a04a10f8SKris Kennaway 			perror("dup2 stdout");
554a04a10f8SKris Kennaway 		close(pout[1]);
555a04a10f8SKris Kennaway 
556a04a10f8SKris Kennaway 		/* Redirect stderr. */
557a04a10f8SKris Kennaway 		close(perr[0]);
558a04a10f8SKris Kennaway 		if (dup2(perr[1], 2) < 0)
559a04a10f8SKris Kennaway 			perror("dup2 stderr");
560a04a10f8SKris Kennaway 		close(perr[1]);
561d4af9e69SDag-Erling Smørgrav #else
562a04a10f8SKris Kennaway 		/*
563a04a10f8SKris Kennaway 		 * Redirect stdin, stdout, and stderr.  Stdin and stdout will
564a04a10f8SKris Kennaway 		 * use the same socket, as some programs (particularly rdist)
565a04a10f8SKris Kennaway 		 * seem to depend on it.
566a04a10f8SKris Kennaway 		 */
567a04a10f8SKris Kennaway 		close(inout[1]);
568a04a10f8SKris Kennaway 		close(err[1]);
569a04a10f8SKris Kennaway 		if (dup2(inout[0], 0) < 0)	/* stdin */
570a04a10f8SKris Kennaway 			perror("dup2 stdin");
571d4af9e69SDag-Erling Smørgrav 		if (dup2(inout[0], 1) < 0)	/* stdout (same as stdin) */
572a04a10f8SKris Kennaway 			perror("dup2 stdout");
573d4af9e69SDag-Erling Smørgrav 		close(inout[0]);
574a04a10f8SKris Kennaway 		if (dup2(err[0], 2) < 0)	/* stderr */
575a04a10f8SKris Kennaway 			perror("dup2 stderr");
576d4af9e69SDag-Erling Smørgrav 		close(err[0]);
577d4af9e69SDag-Erling Smørgrav #endif
578d4af9e69SDag-Erling Smørgrav 
579a04a10f8SKris Kennaway 
580f388f5efSDag-Erling Smørgrav #ifdef _UNICOS
581f388f5efSDag-Erling Smørgrav 		cray_init_job(s->pw); /* set up cray jid and tmpdir */
582f388f5efSDag-Erling Smørgrav #endif
583f388f5efSDag-Erling Smørgrav 
584a04a10f8SKris Kennaway 		/* Do processing for the child (exec command etc). */
585ca3176e7SBrian Feldman 		do_child(s, command);
586a04a10f8SKris Kennaway 		/* NOTREACHED */
587d4af9e69SDag-Erling Smørgrav 	default:
588d4af9e69SDag-Erling Smørgrav 		break;
589a04a10f8SKris Kennaway 	}
590d4af9e69SDag-Erling Smørgrav 
591f388f5efSDag-Erling Smørgrav #ifdef _UNICOS
592f388f5efSDag-Erling Smørgrav 	signal(WJSIGNAL, cray_job_termination_handler);
593f388f5efSDag-Erling Smørgrav #endif /* _UNICOS */
594989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN
595989dd127SDag-Erling Smørgrav 	cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
596989dd127SDag-Erling Smørgrav #endif
597d4af9e69SDag-Erling Smørgrav 
598a04a10f8SKris Kennaway 	s->pid = pid;
599ca3176e7SBrian Feldman 	/* Set interactive/non-interactive mode. */
6004a421b63SDag-Erling Smørgrav 	packet_set_interactive(s->display != NULL,
6014a421b63SDag-Erling Smørgrav 	    options.ip_qos_interactive, options.ip_qos_bulk);
602d4af9e69SDag-Erling Smørgrav 
603d4af9e69SDag-Erling Smørgrav 	/*
604d4af9e69SDag-Erling Smørgrav 	 * Clear loginmsg, since it's the child's responsibility to display
605d4af9e69SDag-Erling Smørgrav 	 * it to the user, otherwise multiple sessions may accumulate
606d4af9e69SDag-Erling Smørgrav 	 * multiple copies of the login messages.
607d4af9e69SDag-Erling Smørgrav 	 */
608d4af9e69SDag-Erling Smørgrav 	buffer_clear(&loginmsg);
609d4af9e69SDag-Erling Smørgrav 
610a04a10f8SKris Kennaway #ifdef USE_PIPES
611a04a10f8SKris Kennaway 	/* We are the parent.  Close the child sides of the pipes. */
612a04a10f8SKris Kennaway 	close(pin[0]);
613a04a10f8SKris Kennaway 	close(pout[1]);
614a04a10f8SKris Kennaway 	close(perr[1]);
615a04a10f8SKris Kennaway 
616a04a10f8SKris Kennaway 	if (compat20) {
617e2f6069cSDag-Erling Smørgrav 		session_set_fds(s, pin[1], pout[0], perr[0],
618e2f6069cSDag-Erling Smørgrav 		    s->is_subsystem, 0);
619a04a10f8SKris Kennaway 	} else {
620a04a10f8SKris Kennaway 		/* Enter the interactive session. */
621a04a10f8SKris Kennaway 		server_loop(pid, pin[1], pout[0], perr[0]);
622ca3176e7SBrian Feldman 		/* server_loop has closed pin[1], pout[0], and perr[0]. */
623a04a10f8SKris Kennaway 	}
624d4af9e69SDag-Erling Smørgrav #else
625a04a10f8SKris Kennaway 	/* We are the parent.  Close the child sides of the socket pairs. */
626a04a10f8SKris Kennaway 	close(inout[0]);
627a04a10f8SKris Kennaway 	close(err[0]);
628a04a10f8SKris Kennaway 
629a04a10f8SKris Kennaway 	/*
630a04a10f8SKris Kennaway 	 * Enter the interactive session.  Note: server_loop must be able to
631a04a10f8SKris Kennaway 	 * handle the case that fdin and fdout are the same.
632a04a10f8SKris Kennaway 	 */
633a04a10f8SKris Kennaway 	if (compat20) {
634e2f6069cSDag-Erling Smørgrav 		session_set_fds(s, inout[1], inout[1], err[1],
635e2f6069cSDag-Erling Smørgrav 		    s->is_subsystem, 0);
636a04a10f8SKris Kennaway 	} else {
637a04a10f8SKris Kennaway 		server_loop(pid, inout[1], inout[1], err[1]);
638a04a10f8SKris Kennaway 		/* server_loop has closed inout[1] and err[1]. */
639a04a10f8SKris Kennaway 	}
640d4af9e69SDag-Erling Smørgrav #endif
641d4af9e69SDag-Erling Smørgrav 	return 0;
642a04a10f8SKris Kennaway }
643a04a10f8SKris Kennaway 
644a04a10f8SKris Kennaway /*
645a04a10f8SKris Kennaway  * This is called to fork and execute a command when we have a tty.  This
646a04a10f8SKris Kennaway  * will call do_child from the child, and server_loop from the parent after
647a04a10f8SKris Kennaway  * setting up file descriptors, controlling tty, updating wtmp, utmp,
648a04a10f8SKris Kennaway  * lastlog, and other such operations.
649a04a10f8SKris Kennaway  */
650d4af9e69SDag-Erling Smørgrav int
651ca3176e7SBrian Feldman do_exec_pty(Session *s, const char *command)
652a04a10f8SKris Kennaway {
653a04a10f8SKris Kennaway 	int fdout, ptyfd, ttyfd, ptymaster;
654a04a10f8SKris Kennaway 	pid_t pid;
655a04a10f8SKris Kennaway 
656a04a10f8SKris Kennaway 	if (s == NULL)
657a04a10f8SKris Kennaway 		fatal("do_exec_pty: no session");
658a04a10f8SKris Kennaway 	ptyfd = s->ptyfd;
659a04a10f8SKris Kennaway 	ttyfd = s->ttyfd;
660a04a10f8SKris Kennaway 
661d4af9e69SDag-Erling Smørgrav 	/*
662d4af9e69SDag-Erling Smørgrav 	 * Create another descriptor of the pty master side for use as the
663d4af9e69SDag-Erling Smørgrav 	 * standard input.  We could use the original descriptor, but this
664d4af9e69SDag-Erling Smørgrav 	 * simplifies code in server_loop.  The descriptor is bidirectional.
665d4af9e69SDag-Erling Smørgrav 	 * Do this before forking (and cleanup in the child) so as to
666d4af9e69SDag-Erling Smørgrav 	 * detect and gracefully fail out-of-fd conditions.
667d4af9e69SDag-Erling Smørgrav 	 */
668d4af9e69SDag-Erling Smørgrav 	if ((fdout = dup(ptyfd)) < 0) {
669d4af9e69SDag-Erling Smørgrav 		error("%s: dup #1: %s", __func__, strerror(errno));
670d4af9e69SDag-Erling Smørgrav 		close(ttyfd);
671d4af9e69SDag-Erling Smørgrav 		close(ptyfd);
672d4af9e69SDag-Erling Smørgrav 		return -1;
673cf2b5f3bSDag-Erling Smørgrav 	}
674d4af9e69SDag-Erling Smørgrav 	/* we keep a reference to the pty master */
675d4af9e69SDag-Erling Smørgrav 	if ((ptymaster = dup(ptyfd)) < 0) {
676d4af9e69SDag-Erling Smørgrav 		error("%s: dup #2: %s", __func__, strerror(errno));
677d4af9e69SDag-Erling Smørgrav 		close(ttyfd);
678d4af9e69SDag-Erling Smørgrav 		close(ptyfd);
679d4af9e69SDag-Erling Smørgrav 		close(fdout);
680d4af9e69SDag-Erling Smørgrav 		return -1;
681d4af9e69SDag-Erling Smørgrav 	}
68209958426SBrian Feldman 
683a04a10f8SKris Kennaway 	/* Fork the child. */
684d4af9e69SDag-Erling Smørgrav 	switch ((pid = fork())) {
685d4af9e69SDag-Erling Smørgrav 	case -1:
686d4af9e69SDag-Erling Smørgrav 		error("%s: fork: %.100s", __func__, strerror(errno));
687d4af9e69SDag-Erling Smørgrav 		close(fdout);
688d4af9e69SDag-Erling Smørgrav 		close(ptymaster);
689d4af9e69SDag-Erling Smørgrav 		close(ttyfd);
690d4af9e69SDag-Erling Smørgrav 		close(ptyfd);
691d4af9e69SDag-Erling Smørgrav 		return -1;
692d4af9e69SDag-Erling Smørgrav 	case 0:
6931ec0d754SDag-Erling Smørgrav 		is_child = 1;
694af12a3e7SDag-Erling Smørgrav 
695d4af9e69SDag-Erling Smørgrav 		close(fdout);
696d4af9e69SDag-Erling Smørgrav 		close(ptymaster);
697d4af9e69SDag-Erling Smørgrav 
698c2d3a559SKris Kennaway 		/* Child.  Reinitialize the log because the pid has changed. */
699d4af9e69SDag-Erling Smørgrav 		log_init(__progname, options.log_level,
700d4af9e69SDag-Erling Smørgrav 		    options.log_facility, log_stderr);
701a04a10f8SKris Kennaway 		/* Close the master side of the pseudo tty. */
702a04a10f8SKris Kennaway 		close(ptyfd);
703a04a10f8SKris Kennaway 
704a04a10f8SKris Kennaway 		/* Make the pseudo tty our controlling tty. */
705a04a10f8SKris Kennaway 		pty_make_controlling_tty(&ttyfd, s->tty);
706a04a10f8SKris Kennaway 
707af12a3e7SDag-Erling Smørgrav 		/* Redirect stdin/stdout/stderr from the pseudo tty. */
708af12a3e7SDag-Erling Smørgrav 		if (dup2(ttyfd, 0) < 0)
709af12a3e7SDag-Erling Smørgrav 			error("dup2 stdin: %s", strerror(errno));
710af12a3e7SDag-Erling Smørgrav 		if (dup2(ttyfd, 1) < 0)
711af12a3e7SDag-Erling Smørgrav 			error("dup2 stdout: %s", strerror(errno));
712af12a3e7SDag-Erling Smørgrav 		if (dup2(ttyfd, 2) < 0)
713af12a3e7SDag-Erling Smørgrav 			error("dup2 stderr: %s", strerror(errno));
714a04a10f8SKris Kennaway 
715a04a10f8SKris Kennaway 		/* Close the extra descriptor for the pseudo tty. */
716a04a10f8SKris Kennaway 		close(ttyfd);
717a04a10f8SKris Kennaway 
718c2d3a559SKris Kennaway 		/* record login, etc. similar to login(1) */
719989dd127SDag-Erling Smørgrav #ifndef HAVE_OSF_SIA
720f388f5efSDag-Erling Smørgrav 		if (!(options.use_login && command == NULL)) {
721f388f5efSDag-Erling Smørgrav #ifdef _UNICOS
722f388f5efSDag-Erling Smørgrav 			cray_init_job(s->pw); /* set up cray jid and tmpdir */
723f388f5efSDag-Erling Smørgrav #endif /* _UNICOS */
724ca3176e7SBrian Feldman 			do_login(s, command);
725f388f5efSDag-Erling Smørgrav 		}
726989dd127SDag-Erling Smørgrav # ifdef LOGIN_NEEDS_UTMPX
727989dd127SDag-Erling Smørgrav 		else
728989dd127SDag-Erling Smørgrav 			do_pre_login(s);
729989dd127SDag-Erling Smørgrav # endif
730989dd127SDag-Erling Smørgrav #endif
731d4af9e69SDag-Erling Smørgrav 		/*
732d4af9e69SDag-Erling Smørgrav 		 * Do common processing for the child, such as execing
733d4af9e69SDag-Erling Smørgrav 		 * the command.
734d4af9e69SDag-Erling Smørgrav 		 */
735ca3176e7SBrian Feldman 		do_child(s, command);
736a04a10f8SKris Kennaway 		/* NOTREACHED */
737d4af9e69SDag-Erling Smørgrav 	default:
738d4af9e69SDag-Erling Smørgrav 		break;
739a04a10f8SKris Kennaway 	}
740d4af9e69SDag-Erling Smørgrav 
741f388f5efSDag-Erling Smørgrav #ifdef _UNICOS
742f388f5efSDag-Erling Smørgrav 	signal(WJSIGNAL, cray_job_termination_handler);
743f388f5efSDag-Erling Smørgrav #endif /* _UNICOS */
744989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN
745989dd127SDag-Erling Smørgrav 	cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
746989dd127SDag-Erling Smørgrav #endif
747d4af9e69SDag-Erling Smørgrav 
748a04a10f8SKris Kennaway 	s->pid = pid;
749a04a10f8SKris Kennaway 
750a04a10f8SKris Kennaway 	/* Parent.  Close the slave side of the pseudo tty. */
751a04a10f8SKris Kennaway 	close(ttyfd);
752a04a10f8SKris Kennaway 
753a04a10f8SKris Kennaway 	/* Enter interactive session. */
754d4af9e69SDag-Erling Smørgrav 	s->ptymaster = ptymaster;
7554a421b63SDag-Erling Smørgrav 	packet_set_interactive(1,
7564a421b63SDag-Erling Smørgrav 	    options.ip_qos_interactive, options.ip_qos_bulk);
757a04a10f8SKris Kennaway 	if (compat20) {
758e2f6069cSDag-Erling Smørgrav 		session_set_fds(s, ptyfd, fdout, -1, 1, 1);
759a04a10f8SKris Kennaway 	} else {
760a04a10f8SKris Kennaway 		server_loop(pid, ptyfd, fdout, -1);
761a04a10f8SKris Kennaway 		/* server_loop _has_ closed ptyfd and fdout. */
762a04a10f8SKris Kennaway 	}
763d4af9e69SDag-Erling Smørgrav 	return 0;
764a04a10f8SKris Kennaway }
765a04a10f8SKris Kennaway 
766989dd127SDag-Erling Smørgrav #ifdef LOGIN_NEEDS_UTMPX
767989dd127SDag-Erling Smørgrav static void
768989dd127SDag-Erling Smørgrav do_pre_login(Session *s)
769989dd127SDag-Erling Smørgrav {
770989dd127SDag-Erling Smørgrav 	socklen_t fromlen;
771989dd127SDag-Erling Smørgrav 	struct sockaddr_storage from;
772989dd127SDag-Erling Smørgrav 	pid_t pid = getpid();
773989dd127SDag-Erling Smørgrav 
774989dd127SDag-Erling Smørgrav 	/*
775989dd127SDag-Erling Smørgrav 	 * Get IP address of client. If the connection is not a socket, let
776989dd127SDag-Erling Smørgrav 	 * the address be 0.0.0.0.
777989dd127SDag-Erling Smørgrav 	 */
778989dd127SDag-Erling Smørgrav 	memset(&from, 0, sizeof(from));
779989dd127SDag-Erling Smørgrav 	fromlen = sizeof(from);
7807ac32603SHajimu UMEMOTO 	if (packet_connection_is_on_socket()) {
781989dd127SDag-Erling Smørgrav 		if (getpeername(packet_get_connection_in(),
782989dd127SDag-Erling Smørgrav 		    (struct sockaddr *)&from, &fromlen) < 0) {
783989dd127SDag-Erling Smørgrav 			debug("getpeername: %.100s", strerror(errno));
7841ec0d754SDag-Erling Smørgrav 			cleanup_exit(255);
785989dd127SDag-Erling Smørgrav 		}
786989dd127SDag-Erling Smørgrav 	}
787989dd127SDag-Erling Smørgrav 
788989dd127SDag-Erling Smørgrav 	record_utmp_only(pid, s->tty, s->pw->pw_name,
789cf2b5f3bSDag-Erling Smørgrav 	    get_remote_name_or_ip(utmp_len, options.use_dns),
7907ac32603SHajimu UMEMOTO 	    (struct sockaddr *)&from, fromlen);
791989dd127SDag-Erling Smørgrav }
792989dd127SDag-Erling Smørgrav #endif
793989dd127SDag-Erling Smørgrav 
794af12a3e7SDag-Erling Smørgrav /*
795af12a3e7SDag-Erling Smørgrav  * This is called to fork and execute a command.  If another command is
796af12a3e7SDag-Erling Smørgrav  * to be forced, execute that instead.
797af12a3e7SDag-Erling Smørgrav  */
798d4af9e69SDag-Erling Smørgrav int
799af12a3e7SDag-Erling Smørgrav do_exec(Session *s, const char *command)
800af12a3e7SDag-Erling Smørgrav {
801d4af9e69SDag-Erling Smørgrav 	int ret;
802d4af9e69SDag-Erling Smørgrav 
803333ee039SDag-Erling Smørgrav 	if (options.adm_forced_command) {
804333ee039SDag-Erling Smørgrav 		original_command = command;
805333ee039SDag-Erling Smørgrav 		command = options.adm_forced_command;
806b15c8340SDag-Erling Smørgrav 		if (IS_INTERNAL_SFTP(command)) {
807b15c8340SDag-Erling Smørgrav 			s->is_subsystem = s->is_subsystem ?
808b15c8340SDag-Erling Smørgrav 			    SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR;
809b15c8340SDag-Erling Smørgrav 		} else if (s->is_subsystem)
810d4af9e69SDag-Erling Smørgrav 			s->is_subsystem = SUBSYSTEM_EXT;
811333ee039SDag-Erling Smørgrav 		debug("Forced command (config) '%.900s'", command);
812333ee039SDag-Erling Smørgrav 	} else if (forced_command) {
813af12a3e7SDag-Erling Smørgrav 		original_command = command;
814af12a3e7SDag-Erling Smørgrav 		command = forced_command;
815b15c8340SDag-Erling Smørgrav 		if (IS_INTERNAL_SFTP(command)) {
816b15c8340SDag-Erling Smørgrav 			s->is_subsystem = s->is_subsystem ?
817b15c8340SDag-Erling Smørgrav 			    SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR;
818b15c8340SDag-Erling Smørgrav 		} else if (s->is_subsystem)
819d4af9e69SDag-Erling Smørgrav 			s->is_subsystem = SUBSYSTEM_EXT;
820333ee039SDag-Erling Smørgrav 		debug("Forced command (key option) '%.900s'", command);
821af12a3e7SDag-Erling Smørgrav 	}
822af12a3e7SDag-Erling Smørgrav 
823aa49c926SDag-Erling Smørgrav #ifdef SSH_AUDIT_EVENTS
824aa49c926SDag-Erling Smørgrav 	if (command != NULL)
825aa49c926SDag-Erling Smørgrav 		PRIVSEP(audit_run_command(command));
826aa49c926SDag-Erling Smørgrav 	else if (s->ttyfd == -1) {
827aa49c926SDag-Erling Smørgrav 		char *shell = s->pw->pw_shell;
828aa49c926SDag-Erling Smørgrav 
829aa49c926SDag-Erling Smørgrav 		if (shell[0] == '\0')	/* empty shell means /bin/sh */
830aa49c926SDag-Erling Smørgrav 			shell =_PATH_BSHELL;
831aa49c926SDag-Erling Smørgrav 		PRIVSEP(audit_run_command(shell));
832cf2b5f3bSDag-Erling Smørgrav 	}
833cf2b5f3bSDag-Erling Smørgrav #endif
834af12a3e7SDag-Erling Smørgrav 	if (s->ttyfd != -1)
835d4af9e69SDag-Erling Smørgrav 		ret = do_exec_pty(s, command);
836af12a3e7SDag-Erling Smørgrav 	else
837d4af9e69SDag-Erling Smørgrav 		ret = do_exec_no_pty(s, command);
838af12a3e7SDag-Erling Smørgrav 
839af12a3e7SDag-Erling Smørgrav 	original_command = NULL;
840af12a3e7SDag-Erling Smørgrav 
84121e764dfSDag-Erling Smørgrav 	/*
84221e764dfSDag-Erling Smørgrav 	 * Clear loginmsg: it's the child's responsibility to display
84321e764dfSDag-Erling Smørgrav 	 * it to the user, otherwise multiple sessions may accumulate
84421e764dfSDag-Erling Smørgrav 	 * multiple copies of the login messages.
84521e764dfSDag-Erling Smørgrav 	 */
84621e764dfSDag-Erling Smørgrav 	buffer_clear(&loginmsg);
847d4af9e69SDag-Erling Smørgrav 
848d4af9e69SDag-Erling Smørgrav 	return ret;
84921e764dfSDag-Erling Smørgrav }
850af12a3e7SDag-Erling Smørgrav 
851c2d3a559SKris Kennaway /* administrative, login(1)-like work */
852ca3176e7SBrian Feldman void
853c2d3a559SKris Kennaway do_login(Session *s, const char *command)
854c2d3a559SKris Kennaway {
855c2d3a559SKris Kennaway 	socklen_t fromlen;
856c2d3a559SKris Kennaway 	struct sockaddr_storage from;
857c2d3a559SKris Kennaway 	struct passwd * pw = s->pw;
858c2d3a559SKris Kennaway 	pid_t pid = getpid();
859c2d3a559SKris Kennaway 
860c2d3a559SKris Kennaway 	/*
861c2d3a559SKris Kennaway 	 * Get IP address of client. If the connection is not a socket, let
862c2d3a559SKris Kennaway 	 * the address be 0.0.0.0.
863c2d3a559SKris Kennaway 	 */
864c2d3a559SKris Kennaway 	memset(&from, 0, sizeof(from));
865c2d3a559SKris Kennaway 	fromlen = sizeof(from);
8667ac32603SHajimu UMEMOTO 	if (packet_connection_is_on_socket()) {
867c2d3a559SKris Kennaway 		if (getpeername(packet_get_connection_in(),
868c2d3a559SKris Kennaway 		    (struct sockaddr *)&from, &fromlen) < 0) {
869c2d3a559SKris Kennaway 			debug("getpeername: %.100s", strerror(errno));
8701ec0d754SDag-Erling Smørgrav 			cleanup_exit(255);
871c2d3a559SKris Kennaway 		}
872c2d3a559SKris Kennaway 	}
873c2d3a559SKris Kennaway 
87480628bacSDag-Erling Smørgrav 	/* Record that there was a login on that tty from the remote host. */
87580628bacSDag-Erling Smørgrav 	if (!use_privsep)
87680628bacSDag-Erling Smørgrav 		record_login(pid, s->tty, pw->pw_name, pw->pw_uid,
87780628bacSDag-Erling Smørgrav 		    get_remote_name_or_ip(utmp_len,
878cf2b5f3bSDag-Erling Smørgrav 		    options.use_dns),
8797ac32603SHajimu UMEMOTO 		    (struct sockaddr *)&from, fromlen);
88080628bacSDag-Erling Smørgrav 
881098de0c1SAndrey A. Chernov #ifdef USE_PAM
882c2d3a559SKris Kennaway 	/*
883989dd127SDag-Erling Smørgrav 	 * If password change is needed, do it now.
884989dd127SDag-Erling Smørgrav 	 * This needs to occur before the ~/.hushlogin check.
885c2d3a559SKris Kennaway 	 */
8861ec0d754SDag-Erling Smørgrav 	if (options.use_pam && !use_privsep && s->authctxt->force_pwchange) {
8871ec0d754SDag-Erling Smørgrav 		display_loginmsg();
888989dd127SDag-Erling Smørgrav 		do_pam_chauthtok();
8891ec0d754SDag-Erling Smørgrav 		s->authctxt->force_pwchange = 0;
890cf2b5f3bSDag-Erling Smørgrav 		/* XXX - signal [net] parent to enable forwardings */
891989dd127SDag-Erling Smørgrav 	}
892989dd127SDag-Erling Smørgrav #endif
893af12a3e7SDag-Erling Smørgrav 
894989dd127SDag-Erling Smørgrav 	if (check_quietlogin(s, command))
895989dd127SDag-Erling Smørgrav 		return;
896989dd127SDag-Erling Smørgrav 
8971ec0d754SDag-Erling Smørgrav 	display_loginmsg();
898f388f5efSDag-Erling Smørgrav 
899ca3176e7SBrian Feldman 	do_motd();
900ca3176e7SBrian Feldman }
901ca3176e7SBrian Feldman 
902ca3176e7SBrian Feldman /*
903ca3176e7SBrian Feldman  * Display the message of the day.
904ca3176e7SBrian Feldman  */
905ca3176e7SBrian Feldman void
906ca3176e7SBrian Feldman do_motd(void)
907ca3176e7SBrian Feldman {
908ca3176e7SBrian Feldman 	FILE *f;
909ca3176e7SBrian Feldman 	char buf[256];
910ca3176e7SBrian Feldman 
911ca3176e7SBrian Feldman 	if (options.print_motd) {
912c2d3a559SKris Kennaway #ifdef HAVE_LOGIN_CAP
913c2d3a559SKris Kennaway 		f = fopen(login_getcapstr(lc, "welcome", "/etc/motd",
914c2d3a559SKris Kennaway 		    "/etc/motd"), "r");
915af12a3e7SDag-Erling Smørgrav #else
916c2d3a559SKris Kennaway 		f = fopen("/etc/motd", "r");
917af12a3e7SDag-Erling Smørgrav #endif
918c2d3a559SKris Kennaway 		if (f) {
919c2d3a559SKris Kennaway 			while (fgets(buf, sizeof(buf), f))
920c2d3a559SKris Kennaway 				fputs(buf, stdout);
921c2d3a559SKris Kennaway 			fclose(f);
922c2d3a559SKris Kennaway 		}
923c2d3a559SKris Kennaway 	}
924ca3176e7SBrian Feldman }
925c2d3a559SKris Kennaway 
926af12a3e7SDag-Erling Smørgrav 
927ca3176e7SBrian Feldman /*
928ca3176e7SBrian Feldman  * Check for quiet login, either .hushlogin or command given.
929ca3176e7SBrian Feldman  */
930ca3176e7SBrian Feldman int
931ca3176e7SBrian Feldman check_quietlogin(Session *s, const char *command)
932ca3176e7SBrian Feldman {
933ca3176e7SBrian Feldman 	char buf[256];
934ca3176e7SBrian Feldman 	struct passwd *pw = s->pw;
935ca3176e7SBrian Feldman 	struct stat st;
936ca3176e7SBrian Feldman 
937ca3176e7SBrian Feldman 	/* Return 1 if .hushlogin exists or a command given. */
938ca3176e7SBrian Feldman 	if (command != NULL)
939ca3176e7SBrian Feldman 		return 1;
940ca3176e7SBrian Feldman 	snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir);
941c2d3a559SKris Kennaway #ifdef HAVE_LOGIN_CAP
942ca3176e7SBrian Feldman 	if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0)
943ca3176e7SBrian Feldman 		return 1;
944ca3176e7SBrian Feldman #else
945ca3176e7SBrian Feldman 	if (stat(buf, &st) >= 0)
946ca3176e7SBrian Feldman 		return 1;
947ca3176e7SBrian Feldman #endif
948ca3176e7SBrian Feldman 	return 0;
949c2d3a559SKris Kennaway }
950c2d3a559SKris Kennaway 
951a04a10f8SKris Kennaway /*
952a04a10f8SKris Kennaway  * Sets the value of the given variable in the environment.  If the variable
953cce7d346SDag-Erling Smørgrav  * already exists, its value is overridden.
954a04a10f8SKris Kennaway  */
955cf2b5f3bSDag-Erling Smørgrav void
956ca3176e7SBrian Feldman child_set_env(char ***envp, u_int *envsizep, const char *name,
957a04a10f8SKris Kennaway 	const char *value)
958a04a10f8SKris Kennaway {
959a04a10f8SKris Kennaway 	char **env;
960b69cd7f2SJacques Vidrine 	u_int envsize;
961b69cd7f2SJacques Vidrine 	u_int i, namelen;
962a04a10f8SKris Kennaway 
963a04a10f8SKris Kennaway 	/*
964cf2b5f3bSDag-Erling Smørgrav 	 * If we're passed an uninitialized list, allocate a single null
965cf2b5f3bSDag-Erling Smørgrav 	 * entry before continuing.
966cf2b5f3bSDag-Erling Smørgrav 	 */
967cf2b5f3bSDag-Erling Smørgrav 	if (*envp == NULL && *envsizep == 0) {
968cf2b5f3bSDag-Erling Smørgrav 		*envp = xmalloc(sizeof(char *));
969cf2b5f3bSDag-Erling Smørgrav 		*envp[0] = NULL;
970cf2b5f3bSDag-Erling Smørgrav 		*envsizep = 1;
971cf2b5f3bSDag-Erling Smørgrav 	}
972cf2b5f3bSDag-Erling Smørgrav 
973cf2b5f3bSDag-Erling Smørgrav 	/*
974a04a10f8SKris Kennaway 	 * Find the slot where the value should be stored.  If the variable
975a04a10f8SKris Kennaway 	 * already exists, we reuse the slot; otherwise we append a new slot
976a04a10f8SKris Kennaway 	 * at the end of the array, expanding if necessary.
977a04a10f8SKris Kennaway 	 */
978a04a10f8SKris Kennaway 	env = *envp;
979a04a10f8SKris Kennaway 	namelen = strlen(name);
980a04a10f8SKris Kennaway 	for (i = 0; env[i]; i++)
981a04a10f8SKris Kennaway 		if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
982a04a10f8SKris Kennaway 			break;
983a04a10f8SKris Kennaway 	if (env[i]) {
984a04a10f8SKris Kennaway 		/* Reuse the slot. */
985a04a10f8SKris Kennaway 		xfree(env[i]);
986a04a10f8SKris Kennaway 	} else {
987a04a10f8SKris Kennaway 		/* New variable.  Expand if necessary. */
988b69cd7f2SJacques Vidrine 		envsize = *envsizep;
989b69cd7f2SJacques Vidrine 		if (i >= envsize - 1) {
990b69cd7f2SJacques Vidrine 			if (envsize >= 1000)
991b69cd7f2SJacques Vidrine 				fatal("child_set_env: too many env vars");
992b69cd7f2SJacques Vidrine 			envsize += 50;
993333ee039SDag-Erling Smørgrav 			env = (*envp) = xrealloc(env, envsize, sizeof(char *));
994b69cd7f2SJacques Vidrine 			*envsizep = envsize;
995a04a10f8SKris Kennaway 		}
996a04a10f8SKris Kennaway 		/* Need to set the NULL pointer at end of array beyond the new slot. */
997a04a10f8SKris Kennaway 		env[i + 1] = NULL;
998a04a10f8SKris Kennaway 	}
999a04a10f8SKris Kennaway 
1000a04a10f8SKris Kennaway 	/* Allocate space and format the variable in the appropriate slot. */
1001a04a10f8SKris Kennaway 	env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
1002a04a10f8SKris Kennaway 	snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
1003a04a10f8SKris Kennaway }
1004a04a10f8SKris Kennaway 
1005a04a10f8SKris Kennaway /*
1006a04a10f8SKris Kennaway  * Reads environment variables from the given file and adds/overrides them
1007a04a10f8SKris Kennaway  * into the environment.  If the file does not exist, this does nothing.
1008a04a10f8SKris Kennaway  * Otherwise, it must consist of empty lines, comments (line starts with '#')
1009a04a10f8SKris Kennaway  * and assignments of the form name=value.  No other forms are allowed.
1010a04a10f8SKris Kennaway  */
1011af12a3e7SDag-Erling Smørgrav static void
1012ca3176e7SBrian Feldman read_environment_file(char ***env, u_int *envsize,
1013a04a10f8SKris Kennaway 	const char *filename)
1014a04a10f8SKris Kennaway {
1015a04a10f8SKris Kennaway 	FILE *f;
1016a04a10f8SKris Kennaway 	char buf[4096];
1017a04a10f8SKris Kennaway 	char *cp, *value;
1018a82e551fSDag-Erling Smørgrav 	u_int lineno = 0;
1019a04a10f8SKris Kennaway 
1020a04a10f8SKris Kennaway 	f = fopen(filename, "r");
1021a04a10f8SKris Kennaway 	if (!f)
1022a04a10f8SKris Kennaway 		return;
1023a04a10f8SKris Kennaway 
1024a04a10f8SKris Kennaway 	while (fgets(buf, sizeof(buf), f)) {
1025a82e551fSDag-Erling Smørgrav 		if (++lineno > 1000)
1026a82e551fSDag-Erling Smørgrav 			fatal("Too many lines in environment file %s", filename);
1027a04a10f8SKris Kennaway 		for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
1028a04a10f8SKris Kennaway 			;
1029a04a10f8SKris Kennaway 		if (!*cp || *cp == '#' || *cp == '\n')
1030a04a10f8SKris Kennaway 			continue;
1031d4af9e69SDag-Erling Smørgrav 
1032d4af9e69SDag-Erling Smørgrav 		cp[strcspn(cp, "\n")] = '\0';
1033d4af9e69SDag-Erling Smørgrav 
1034a04a10f8SKris Kennaway 		value = strchr(cp, '=');
1035a04a10f8SKris Kennaway 		if (value == NULL) {
1036a82e551fSDag-Erling Smørgrav 			fprintf(stderr, "Bad line %u in %.100s\n", lineno,
1037a82e551fSDag-Erling Smørgrav 			    filename);
1038a04a10f8SKris Kennaway 			continue;
1039a04a10f8SKris Kennaway 		}
1040db1cb46cSKris Kennaway 		/*
1041db1cb46cSKris Kennaway 		 * Replace the equals sign by nul, and advance value to
1042db1cb46cSKris Kennaway 		 * the value string.
1043db1cb46cSKris Kennaway 		 */
1044a04a10f8SKris Kennaway 		*value = '\0';
1045a04a10f8SKris Kennaway 		value++;
1046a04a10f8SKris Kennaway 		child_set_env(env, envsize, cp, value);
1047a04a10f8SKris Kennaway 	}
1048a04a10f8SKris Kennaway 	fclose(f);
1049a04a10f8SKris Kennaway }
1050a04a10f8SKris Kennaway 
1051cf2b5f3bSDag-Erling Smørgrav #ifdef HAVE_ETC_DEFAULT_LOGIN
1052cf2b5f3bSDag-Erling Smørgrav /*
1053cf2b5f3bSDag-Erling Smørgrav  * Return named variable from specified environment, or NULL if not present.
1054cf2b5f3bSDag-Erling Smørgrav  */
1055cf2b5f3bSDag-Erling Smørgrav static char *
1056cf2b5f3bSDag-Erling Smørgrav child_get_env(char **env, const char *name)
1057cf2b5f3bSDag-Erling Smørgrav {
1058cf2b5f3bSDag-Erling Smørgrav 	int i;
1059cf2b5f3bSDag-Erling Smørgrav 	size_t len;
1060cf2b5f3bSDag-Erling Smørgrav 
1061cf2b5f3bSDag-Erling Smørgrav 	len = strlen(name);
1062cf2b5f3bSDag-Erling Smørgrav 	for (i=0; env[i] != NULL; i++)
1063cf2b5f3bSDag-Erling Smørgrav 		if (strncmp(name, env[i], len) == 0 && env[i][len] == '=')
1064cf2b5f3bSDag-Erling Smørgrav 			return(env[i] + len + 1);
1065cf2b5f3bSDag-Erling Smørgrav 	return NULL;
1066cf2b5f3bSDag-Erling Smørgrav }
1067cf2b5f3bSDag-Erling Smørgrav 
1068cf2b5f3bSDag-Erling Smørgrav /*
1069cf2b5f3bSDag-Erling Smørgrav  * Read /etc/default/login.
1070cf2b5f3bSDag-Erling Smørgrav  * We pick up the PATH (or SUPATH for root) and UMASK.
1071cf2b5f3bSDag-Erling Smørgrav  */
1072cf2b5f3bSDag-Erling Smørgrav static void
1073cf2b5f3bSDag-Erling Smørgrav read_etc_default_login(char ***env, u_int *envsize, uid_t uid)
1074cf2b5f3bSDag-Erling Smørgrav {
1075cf2b5f3bSDag-Erling Smørgrav 	char **tmpenv = NULL, *var;
1076cf2b5f3bSDag-Erling Smørgrav 	u_int i, tmpenvsize = 0;
10771ec0d754SDag-Erling Smørgrav 	u_long mask;
1078cf2b5f3bSDag-Erling Smørgrav 
1079cf2b5f3bSDag-Erling Smørgrav 	/*
1080cf2b5f3bSDag-Erling Smørgrav 	 * We don't want to copy the whole file to the child's environment,
1081cf2b5f3bSDag-Erling Smørgrav 	 * so we use a temporary environment and copy the variables we're
1082cf2b5f3bSDag-Erling Smørgrav 	 * interested in.
1083cf2b5f3bSDag-Erling Smørgrav 	 */
1084cf2b5f3bSDag-Erling Smørgrav 	read_environment_file(&tmpenv, &tmpenvsize, "/etc/default/login");
1085cf2b5f3bSDag-Erling Smørgrav 
1086cf2b5f3bSDag-Erling Smørgrav 	if (tmpenv == NULL)
1087cf2b5f3bSDag-Erling Smørgrav 		return;
1088cf2b5f3bSDag-Erling Smørgrav 
1089cf2b5f3bSDag-Erling Smørgrav 	if (uid == 0)
1090cf2b5f3bSDag-Erling Smørgrav 		var = child_get_env(tmpenv, "SUPATH");
1091cf2b5f3bSDag-Erling Smørgrav 	else
1092cf2b5f3bSDag-Erling Smørgrav 		var = child_get_env(tmpenv, "PATH");
1093cf2b5f3bSDag-Erling Smørgrav 	if (var != NULL)
1094cf2b5f3bSDag-Erling Smørgrav 		child_set_env(env, envsize, "PATH", var);
1095cf2b5f3bSDag-Erling Smørgrav 
1096cf2b5f3bSDag-Erling Smørgrav 	if ((var = child_get_env(tmpenv, "UMASK")) != NULL)
1097cf2b5f3bSDag-Erling Smørgrav 		if (sscanf(var, "%5lo", &mask) == 1)
10981ec0d754SDag-Erling Smørgrav 			umask((mode_t)mask);
1099cf2b5f3bSDag-Erling Smørgrav 
1100cf2b5f3bSDag-Erling Smørgrav 	for (i = 0; tmpenv[i] != NULL; i++)
1101cf2b5f3bSDag-Erling Smørgrav 		xfree(tmpenv[i]);
1102cf2b5f3bSDag-Erling Smørgrav 	xfree(tmpenv);
1103cf2b5f3bSDag-Erling Smørgrav }
1104cf2b5f3bSDag-Erling Smørgrav #endif /* HAVE_ETC_DEFAULT_LOGIN */
1105cf2b5f3bSDag-Erling Smørgrav 
1106d4ecd108SDag-Erling Smørgrav void
1107d4ecd108SDag-Erling Smørgrav copy_environment(char **source, char ***env, u_int *envsize)
110809958426SBrian Feldman {
1109989dd127SDag-Erling Smørgrav 	char *var_name, *var_val;
111009958426SBrian Feldman 	int i;
111109958426SBrian Feldman 
1112989dd127SDag-Erling Smørgrav 	if (source == NULL)
111309958426SBrian Feldman 		return;
111409958426SBrian Feldman 
1115989dd127SDag-Erling Smørgrav 	for(i = 0; source[i] != NULL; i++) {
1116989dd127SDag-Erling Smørgrav 		var_name = xstrdup(source[i]);
1117989dd127SDag-Erling Smørgrav 		if ((var_val = strstr(var_name, "=")) == NULL) {
1118989dd127SDag-Erling Smørgrav 			xfree(var_name);
111909958426SBrian Feldman 			continue;
1120989dd127SDag-Erling Smørgrav 		}
1121989dd127SDag-Erling Smørgrav 		*var_val++ = '\0';
112209958426SBrian Feldman 
1123989dd127SDag-Erling Smørgrav 		debug3("Copy environment: %s=%s", var_name, var_val);
112409958426SBrian Feldman 		child_set_env(env, envsize, var_name, var_val);
1125989dd127SDag-Erling Smørgrav 
1126989dd127SDag-Erling Smørgrav 		xfree(var_name);
112709958426SBrian Feldman 	}
112809958426SBrian Feldman }
112909958426SBrian Feldman 
1130af12a3e7SDag-Erling Smørgrav static char **
1131989dd127SDag-Erling Smørgrav do_setup_env(Session *s, const char *shell)
1132a04a10f8SKris Kennaway {
1133a04a10f8SKris Kennaway 	char buf[256];
1134af12a3e7SDag-Erling Smørgrav 	u_int i, envsize;
1135333ee039SDag-Erling Smørgrav 	char **env, *laddr;
1136333ee039SDag-Erling Smørgrav 	struct passwd *pw = s->pw;
11377aee6ffeSDag-Erling Smørgrav #if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN)
1138333ee039SDag-Erling Smørgrav 	char *path = NULL;
1139333ee039SDag-Erling Smørgrav #else
1140c62005fcSDag-Erling Smørgrav 	extern char **environ;
1141c62005fcSDag-Erling Smørgrav 	char **senv, **var;
1142c62005fcSDag-Erling Smørgrav #endif
1143a04a10f8SKris Kennaway 
1144a04a10f8SKris Kennaway 	/* Initialize the environment. */
1145a04a10f8SKris Kennaway 	envsize = 100;
1146333ee039SDag-Erling Smørgrav 	env = xcalloc(envsize, sizeof(char *));
1147a04a10f8SKris Kennaway 	env[0] = NULL;
1148989dd127SDag-Erling Smørgrav 
1149989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN
1150989dd127SDag-Erling Smørgrav 	/*
1151989dd127SDag-Erling Smørgrav 	 * The Windows environment contains some setting which are
1152989dd127SDag-Erling Smørgrav 	 * important for a running system. They must not be dropped.
1153989dd127SDag-Erling Smørgrav 	 */
1154aa49c926SDag-Erling Smørgrav 	{
1155aa49c926SDag-Erling Smørgrav 		char **p;
1156aa49c926SDag-Erling Smørgrav 
1157aa49c926SDag-Erling Smørgrav 		p = fetch_windows_environment();
1158aa49c926SDag-Erling Smørgrav 		copy_environment(p, &env, &envsize);
1159aa49c926SDag-Erling Smørgrav 		free_windows_environment(p);
1160aa49c926SDag-Erling Smørgrav 	}
1161989dd127SDag-Erling Smørgrav #endif
1162a04a10f8SKris Kennaway 
1163c62005fcSDag-Erling Smørgrav 	if (getenv("TZ"))
1164c62005fcSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "TZ", getenv("TZ"));
1165cf2b5f3bSDag-Erling Smørgrav 
1166cf2b5f3bSDag-Erling Smørgrav #ifdef GSSAPI
1167cf2b5f3bSDag-Erling Smørgrav 	/* Allow any GSSAPI methods that we've used to alter
1168cf2b5f3bSDag-Erling Smørgrav 	 * the childs environment as they see fit
1169cf2b5f3bSDag-Erling Smørgrav 	 */
1170cf2b5f3bSDag-Erling Smørgrav 	ssh_gssapi_do_child(&env, &envsize);
1171cf2b5f3bSDag-Erling Smørgrav #endif
1172cf2b5f3bSDag-Erling Smørgrav 
1173a04a10f8SKris Kennaway 	if (!options.use_login) {
1174a04a10f8SKris Kennaway 		/* Set basic environment. */
117521e764dfSDag-Erling Smørgrav 		for (i = 0; i < s->num_env; i++)
117621e764dfSDag-Erling Smørgrav 			child_set_env(&env, &envsize, s->env[i].name,
117721e764dfSDag-Erling Smørgrav 			    s->env[i].val);
117821e764dfSDag-Erling Smørgrav 
1179a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, "USER", pw->pw_name);
1180a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
1181e73e9afaSDag-Erling Smørgrav #ifdef _AIX
1182e73e9afaSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "LOGIN", pw->pw_name);
1183e73e9afaSDag-Erling Smørgrav #endif
1184a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, "HOME", pw->pw_dir);
1185c62005fcSDag-Erling Smørgrav 		snprintf(buf, sizeof buf, "%.200s/%.50s",
1186c62005fcSDag-Erling Smørgrav 			 _PATH_MAILDIR, pw->pw_name);
1187c62005fcSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "MAIL", buf);
1188989dd127SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1189c62005fcSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
1190c62005fcSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "TERM", "su");
1191c62005fcSDag-Erling Smørgrav 		senv = environ;
1192c62005fcSDag-Erling Smørgrav 		environ = xmalloc(sizeof(char *));
1193c62005fcSDag-Erling Smørgrav 		*environ = NULL;
1194c62005fcSDag-Erling Smørgrav 		(void) setusercontext(lc, pw, pw->pw_uid,
1195c62005fcSDag-Erling Smørgrav 		    LOGIN_SETENV|LOGIN_SETPATH);
1196c62005fcSDag-Erling Smørgrav 		copy_environment(environ, &env, &envsize);
1197c62005fcSDag-Erling Smørgrav 		for (var = environ; *var != NULL; ++var)
1198c62005fcSDag-Erling Smørgrav 			xfree(*var);
1199c62005fcSDag-Erling Smørgrav 		xfree(environ);
1200c62005fcSDag-Erling Smørgrav 		environ = senv;
1201989dd127SDag-Erling Smørgrav #else /* HAVE_LOGIN_CAP */
1202989dd127SDag-Erling Smørgrav # ifndef HAVE_CYGWIN
1203989dd127SDag-Erling Smørgrav 		/*
1204989dd127SDag-Erling Smørgrav 		 * There's no standard path on Windows. The path contains
1205989dd127SDag-Erling Smørgrav 		 * important components pointing to the system directories,
1206989dd127SDag-Erling Smørgrav 		 * needed for loading shared libraries. So the path better
1207989dd127SDag-Erling Smørgrav 		 * remains intact here.
1208989dd127SDag-Erling Smørgrav 		 */
1209cf2b5f3bSDag-Erling Smørgrav #  ifdef HAVE_ETC_DEFAULT_LOGIN
1210cf2b5f3bSDag-Erling Smørgrav 		read_etc_default_login(&env, &envsize, pw->pw_uid);
1211cf2b5f3bSDag-Erling Smørgrav 		path = child_get_env(env, "PATH");
1212cf2b5f3bSDag-Erling Smørgrav #  endif /* HAVE_ETC_DEFAULT_LOGIN */
1213cf2b5f3bSDag-Erling Smørgrav 		if (path == NULL || *path == '\0') {
1214989dd127SDag-Erling Smørgrav 			child_set_env(&env, &envsize, "PATH",
1215cf2b5f3bSDag-Erling Smørgrav 			    s->pw->pw_uid == 0 ?
1216cf2b5f3bSDag-Erling Smørgrav 				SUPERUSER_PATH : _PATH_STDPATH);
1217cf2b5f3bSDag-Erling Smørgrav 		}
1218989dd127SDag-Erling Smørgrav # endif /* HAVE_CYGWIN */
1219989dd127SDag-Erling Smørgrav #endif /* HAVE_LOGIN_CAP */
1220a04a10f8SKris Kennaway 
1221a04a10f8SKris Kennaway 		/* Normal systems set SHELL by default. */
1222a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, "SHELL", shell);
1223a04a10f8SKris Kennaway 	}
1224a04a10f8SKris Kennaway 
1225a04a10f8SKris Kennaway 	/* Set custom environment options from RSA authentication. */
12261c5093bbSJacques Vidrine 	if (!options.use_login) {
1227a04a10f8SKris Kennaway 		while (custom_environment) {
1228a04a10f8SKris Kennaway 			struct envstring *ce = custom_environment;
1229f388f5efSDag-Erling Smørgrav 			char *str = ce->s;
1230af12a3e7SDag-Erling Smørgrav 
1231f388f5efSDag-Erling Smørgrav 			for (i = 0; str[i] != '=' && str[i]; i++)
1232af12a3e7SDag-Erling Smørgrav 				;
1233f388f5efSDag-Erling Smørgrav 			if (str[i] == '=') {
1234f388f5efSDag-Erling Smørgrav 				str[i] = 0;
1235f388f5efSDag-Erling Smørgrav 				child_set_env(&env, &envsize, str, str + i + 1);
1236a04a10f8SKris Kennaway 			}
1237a04a10f8SKris Kennaway 			custom_environment = ce->next;
1238a04a10f8SKris Kennaway 			xfree(ce->s);
1239a04a10f8SKris Kennaway 			xfree(ce);
1240a04a10f8SKris Kennaway 		}
12411c5093bbSJacques Vidrine 	}
1242a04a10f8SKris Kennaway 
1243f388f5efSDag-Erling Smørgrav 	/* SSH_CLIENT deprecated */
1244a04a10f8SKris Kennaway 	snprintf(buf, sizeof buf, "%.50s %d %d",
1245a04a10f8SKris Kennaway 	    get_remote_ipaddr(), get_remote_port(), get_local_port());
1246a04a10f8SKris Kennaway 	child_set_env(&env, &envsize, "SSH_CLIENT", buf);
1247a04a10f8SKris Kennaway 
1248e73e9afaSDag-Erling Smørgrav 	laddr = get_local_ipaddr(packet_get_connection_in());
1249f388f5efSDag-Erling Smørgrav 	snprintf(buf, sizeof buf, "%.50s %d %.50s %d",
1250e73e9afaSDag-Erling Smørgrav 	    get_remote_ipaddr(), get_remote_port(), laddr, get_local_port());
1251e73e9afaSDag-Erling Smørgrav 	xfree(laddr);
1252f388f5efSDag-Erling Smørgrav 	child_set_env(&env, &envsize, "SSH_CONNECTION", buf);
1253f388f5efSDag-Erling Smørgrav 
1254ca3176e7SBrian Feldman 	if (s->ttyfd != -1)
1255ca3176e7SBrian Feldman 		child_set_env(&env, &envsize, "SSH_TTY", s->tty);
1256ca3176e7SBrian Feldman 	if (s->term)
1257ca3176e7SBrian Feldman 		child_set_env(&env, &envsize, "TERM", s->term);
1258ca3176e7SBrian Feldman 	if (s->display)
1259ca3176e7SBrian Feldman 		child_set_env(&env, &envsize, "DISPLAY", s->display);
1260c2d3a559SKris Kennaway 	if (original_command)
1261c2d3a559SKris Kennaway 		child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND",
1262c2d3a559SKris Kennaway 		    original_command);
1263989dd127SDag-Erling Smørgrav 
1264f388f5efSDag-Erling Smørgrav #ifdef _UNICOS
1265f388f5efSDag-Erling Smørgrav 	if (cray_tmpdir[0] != '\0')
1266f388f5efSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "TMPDIR", cray_tmpdir);
1267f388f5efSDag-Erling Smørgrav #endif /* _UNICOS */
1268f388f5efSDag-Erling Smørgrav 
1269aa49c926SDag-Erling Smørgrav 	/*
1270aa49c926SDag-Erling Smørgrav 	 * Since we clear KRB5CCNAME at startup, if it's set now then it
1271aa49c926SDag-Erling Smørgrav 	 * must have been set by a native authentication method (eg AIX or
1272aa49c926SDag-Erling Smørgrav 	 * SIA), so copy it to the child.
1273aa49c926SDag-Erling Smørgrav 	 */
1274aa49c926SDag-Erling Smørgrav 	{
1275aa49c926SDag-Erling Smørgrav 		char *cp;
1276aa49c926SDag-Erling Smørgrav 
1277aa49c926SDag-Erling Smørgrav 		if ((cp = getenv("KRB5CCNAME")) != NULL)
1278aa49c926SDag-Erling Smørgrav 			child_set_env(&env, &envsize, "KRB5CCNAME", cp);
1279aa49c926SDag-Erling Smørgrav 	}
1280aa49c926SDag-Erling Smørgrav 
1281989dd127SDag-Erling Smørgrav #ifdef _AIX
1282989dd127SDag-Erling Smørgrav 	{
1283989dd127SDag-Erling Smørgrav 		char *cp;
1284989dd127SDag-Erling Smørgrav 
1285989dd127SDag-Erling Smørgrav 		if ((cp = getenv("AUTHSTATE")) != NULL)
1286989dd127SDag-Erling Smørgrav 			child_set_env(&env, &envsize, "AUTHSTATE", cp);
1287989dd127SDag-Erling Smørgrav 		read_environment_file(&env, &envsize, "/etc/environment");
1288989dd127SDag-Erling Smørgrav 	}
1289989dd127SDag-Erling Smørgrav #endif
1290e8aafc91SKris Kennaway #ifdef KRB5
12915962c0e9SDag-Erling Smørgrav 	if (s->authctxt->krb5_ccname)
1292af12a3e7SDag-Erling Smørgrav 		child_set_env(&env, &envsize, "KRB5CCNAME",
12935962c0e9SDag-Erling Smørgrav 		    s->authctxt->krb5_ccname);
1294af12a3e7SDag-Erling Smørgrav #endif
129509958426SBrian Feldman #ifdef USE_PAM
1296f388f5efSDag-Erling Smørgrav 	/*
1297f388f5efSDag-Erling Smørgrav 	 * Pull in any environment variables that may have
1298f388f5efSDag-Erling Smørgrav 	 * been set by PAM.
1299f388f5efSDag-Erling Smørgrav 	 */
1300cf2b5f3bSDag-Erling Smørgrav 	if (options.use_pam) {
13011ec0d754SDag-Erling Smørgrav 		char **p;
1302f388f5efSDag-Erling Smørgrav 
13031ec0d754SDag-Erling Smørgrav 		p = fetch_pam_child_environment();
13041ec0d754SDag-Erling Smørgrav 		copy_environment(p, &env, &envsize);
13051ec0d754SDag-Erling Smørgrav 		free_pam_environment(p);
13061ec0d754SDag-Erling Smørgrav 
13071ec0d754SDag-Erling Smørgrav 		p = fetch_pam_environment();
1308f388f5efSDag-Erling Smørgrav 		copy_environment(p, &env, &envsize);
1309f388f5efSDag-Erling Smørgrav 		free_pam_environment(p);
1310f388f5efSDag-Erling Smørgrav 	}
131109958426SBrian Feldman #endif /* USE_PAM */
131209958426SBrian Feldman 
131380628bacSDag-Erling Smørgrav 	if (auth_sock_name != NULL)
1314a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
131580628bacSDag-Erling Smørgrav 		    auth_sock_name);
1316a04a10f8SKris Kennaway 
1317a04a10f8SKris Kennaway 	/* read $HOME/.ssh/environment. */
1318f388f5efSDag-Erling Smørgrav 	if (options.permit_user_env && !options.use_login) {
1319db1cb46cSKris Kennaway 		snprintf(buf, sizeof buf, "%.200s/.ssh/environment",
1320f388f5efSDag-Erling Smørgrav 		    strcmp(pw->pw_dir, "/") ? pw->pw_dir : "");
1321a04a10f8SKris Kennaway 		read_environment_file(&env, &envsize, buf);
1322a04a10f8SKris Kennaway 	}
1323a04a10f8SKris Kennaway 	if (debug_flag) {
1324a04a10f8SKris Kennaway 		/* dump the environment */
1325a04a10f8SKris Kennaway 		fprintf(stderr, "Environment:\n");
1326a04a10f8SKris Kennaway 		for (i = 0; env[i]; i++)
1327a04a10f8SKris Kennaway 			fprintf(stderr, "  %.200s\n", env[i]);
1328a04a10f8SKris Kennaway 	}
1329af12a3e7SDag-Erling Smørgrav 	return env;
1330e8aafc91SKris Kennaway }
1331ca3176e7SBrian Feldman 
1332ca3176e7SBrian Feldman /*
1333af12a3e7SDag-Erling Smørgrav  * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found
1334af12a3e7SDag-Erling Smørgrav  * first in this order).
1335ca3176e7SBrian Feldman  */
1336af12a3e7SDag-Erling Smørgrav static void
1337af12a3e7SDag-Erling Smørgrav do_rc_files(Session *s, const char *shell)
1338af12a3e7SDag-Erling Smørgrav {
1339af12a3e7SDag-Erling Smørgrav 	FILE *f = NULL;
1340af12a3e7SDag-Erling Smørgrav 	char cmd[1024];
1341af12a3e7SDag-Erling Smørgrav 	int do_xauth;
1342af12a3e7SDag-Erling Smørgrav 	struct stat st;
1343a04a10f8SKris Kennaway 
1344af12a3e7SDag-Erling Smørgrav 	do_xauth =
1345af12a3e7SDag-Erling Smørgrav 	    s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL;
1346a04a10f8SKris Kennaway 
1347d4af9e69SDag-Erling Smørgrav 	/* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */
1348d4af9e69SDag-Erling Smørgrav 	if (!s->is_subsystem && options.adm_forced_command == NULL &&
1349d4af9e69SDag-Erling Smørgrav 	    !no_user_rc && stat(_PATH_SSH_USER_RC, &st) >= 0) {
1350e9fd63dfSBrian Feldman 		snprintf(cmd, sizeof cmd, "%s -c '%s %s'",
1351e9fd63dfSBrian Feldman 		    shell, _PATH_BSHELL, _PATH_SSH_USER_RC);
1352a04a10f8SKris Kennaway 		if (debug_flag)
1353e9fd63dfSBrian Feldman 			fprintf(stderr, "Running %s\n", cmd);
1354e9fd63dfSBrian Feldman 		f = popen(cmd, "w");
1355a04a10f8SKris Kennaway 		if (f) {
1356ca3176e7SBrian Feldman 			if (do_xauth)
1357ca3176e7SBrian Feldman 				fprintf(f, "%s %s\n", s->auth_proto,
1358ca3176e7SBrian Feldman 				    s->auth_data);
1359a04a10f8SKris Kennaway 			pclose(f);
1360a04a10f8SKris Kennaway 		} else
1361ca3176e7SBrian Feldman 			fprintf(stderr, "Could not run %s\n",
1362ca3176e7SBrian Feldman 			    _PATH_SSH_USER_RC);
1363ca3176e7SBrian Feldman 	} else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) {
1364a04a10f8SKris Kennaway 		if (debug_flag)
1365ca3176e7SBrian Feldman 			fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,
1366ca3176e7SBrian Feldman 			    _PATH_SSH_SYSTEM_RC);
1367ca3176e7SBrian Feldman 		f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w");
1368a04a10f8SKris Kennaway 		if (f) {
1369ca3176e7SBrian Feldman 			if (do_xauth)
1370ca3176e7SBrian Feldman 				fprintf(f, "%s %s\n", s->auth_proto,
1371ca3176e7SBrian Feldman 				    s->auth_data);
1372a04a10f8SKris Kennaway 			pclose(f);
1373a04a10f8SKris Kennaway 		} else
1374ca3176e7SBrian Feldman 			fprintf(stderr, "Could not run %s\n",
1375ca3176e7SBrian Feldman 			    _PATH_SSH_SYSTEM_RC);
1376ca3176e7SBrian Feldman 	} else if (do_xauth && options.xauth_location != NULL) {
1377a04a10f8SKris Kennaway 		/* Add authority data to .Xauthority if appropriate. */
1378db1cb46cSKris Kennaway 		if (debug_flag) {
1379db1cb46cSKris Kennaway 			fprintf(stderr,
1380e73e9afaSDag-Erling Smørgrav 			    "Running %.500s remove %.100s\n",
1381e73e9afaSDag-Erling Smørgrav 			    options.xauth_location, s->auth_display);
1382e73e9afaSDag-Erling Smørgrav 			fprintf(stderr,
1383e73e9afaSDag-Erling Smørgrav 			    "%.500s add %.100s %.100s %.100s\n",
1384af12a3e7SDag-Erling Smørgrav 			    options.xauth_location, s->auth_display,
1385ca3176e7SBrian Feldman 			    s->auth_proto, s->auth_data);
1386db1cb46cSKris Kennaway 		}
1387c2d3a559SKris Kennaway 		snprintf(cmd, sizeof cmd, "%s -q -",
1388c2d3a559SKris Kennaway 		    options.xauth_location);
1389c2d3a559SKris Kennaway 		f = popen(cmd, "w");
1390a04a10f8SKris Kennaway 		if (f) {
1391e73e9afaSDag-Erling Smørgrav 			fprintf(f, "remove %s\n",
1392e73e9afaSDag-Erling Smørgrav 			    s->auth_display);
1393af12a3e7SDag-Erling Smørgrav 			fprintf(f, "add %s %s %s\n",
1394af12a3e7SDag-Erling Smørgrav 			    s->auth_display, s->auth_proto,
1395ca3176e7SBrian Feldman 			    s->auth_data);
1396a04a10f8SKris Kennaway 			pclose(f);
1397c2d3a559SKris Kennaway 		} else {
1398c2d3a559SKris Kennaway 			fprintf(stderr, "Could not run %s\n",
1399c2d3a559SKris Kennaway 			    cmd);
1400a04a10f8SKris Kennaway 		}
1401a04a10f8SKris Kennaway 	}
1402a04a10f8SKris Kennaway }
1403ca3176e7SBrian Feldman 
1404af12a3e7SDag-Erling Smørgrav static void
1405af12a3e7SDag-Erling Smørgrav do_nologin(struct passwd *pw)
1406af12a3e7SDag-Erling Smørgrav {
1407af12a3e7SDag-Erling Smørgrav 	FILE *f = NULL;
1408b15c8340SDag-Erling Smørgrav 	char buf[1024], *nl, *def_nl = _PATH_NOLOGIN;
1409b15c8340SDag-Erling Smørgrav 	struct stat sb;
1410af12a3e7SDag-Erling Smørgrav 
1411af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1412462c32cbSDag-Erling Smørgrav 	if (login_getcapbool(lc, "ignorenologin", 0) || pw->pw_uid == 0)
1413b15c8340SDag-Erling Smørgrav 		return;
1414b15c8340SDag-Erling Smørgrav 	nl = login_getcapstr(lc, "nologin", def_nl, def_nl);
1415af12a3e7SDag-Erling Smørgrav #else
1416b15c8340SDag-Erling Smørgrav 	if (pw->pw_uid == 0)
1417b15c8340SDag-Erling Smørgrav 		return;
1418b15c8340SDag-Erling Smørgrav 	nl = def_nl;
1419af12a3e7SDag-Erling Smørgrav #endif
1420b15c8340SDag-Erling Smørgrav 	if (stat(nl, &sb) == -1) {
1421b15c8340SDag-Erling Smørgrav 		if (nl != def_nl)
1422b15c8340SDag-Erling Smørgrav 			xfree(nl);
1423b15c8340SDag-Erling Smørgrav 		return;
1424b15c8340SDag-Erling Smørgrav 	}
1425b15c8340SDag-Erling Smørgrav 
1426b15c8340SDag-Erling Smørgrav 	/* /etc/nologin exists.  Print its contents if we can and exit. */
1427b15c8340SDag-Erling Smørgrav 	logit("User %.100s not allowed because %s exists", pw->pw_name, nl);
1428b15c8340SDag-Erling Smørgrav 	if ((f = fopen(nl, "r")) != NULL) {
1429af12a3e7SDag-Erling Smørgrav  		while (fgets(buf, sizeof(buf), f))
1430af12a3e7SDag-Erling Smørgrav  			fputs(buf, stderr);
1431af12a3e7SDag-Erling Smørgrav  		fclose(f);
1432af12a3e7SDag-Erling Smørgrav  	}
1433b15c8340SDag-Erling Smørgrav 	exit(254);
1434af12a3e7SDag-Erling Smørgrav }
1435af12a3e7SDag-Erling Smørgrav 
1436d4af9e69SDag-Erling Smørgrav /*
1437d4af9e69SDag-Erling Smørgrav  * Chroot into a directory after checking it for safety: all path components
1438d4af9e69SDag-Erling Smørgrav  * must be root-owned directories with strict permissions.
1439d4af9e69SDag-Erling Smørgrav  */
1440d4af9e69SDag-Erling Smørgrav static void
1441d4af9e69SDag-Erling Smørgrav safely_chroot(const char *path, uid_t uid)
1442d4af9e69SDag-Erling Smørgrav {
1443d4af9e69SDag-Erling Smørgrav 	const char *cp;
1444d4af9e69SDag-Erling Smørgrav 	char component[MAXPATHLEN];
1445d4af9e69SDag-Erling Smørgrav 	struct stat st;
1446d4af9e69SDag-Erling Smørgrav 
1447d4af9e69SDag-Erling Smørgrav 	if (*path != '/')
1448d4af9e69SDag-Erling Smørgrav 		fatal("chroot path does not begin at root");
1449d4af9e69SDag-Erling Smørgrav 	if (strlen(path) >= sizeof(component))
1450d4af9e69SDag-Erling Smørgrav 		fatal("chroot path too long");
1451d4af9e69SDag-Erling Smørgrav 
1452d4af9e69SDag-Erling Smørgrav 	/*
1453d4af9e69SDag-Erling Smørgrav 	 * Descend the path, checking that each component is a
1454d4af9e69SDag-Erling Smørgrav 	 * root-owned directory with strict permissions.
1455d4af9e69SDag-Erling Smørgrav 	 */
1456d4af9e69SDag-Erling Smørgrav 	for (cp = path; cp != NULL;) {
1457d4af9e69SDag-Erling Smørgrav 		if ((cp = strchr(cp, '/')) == NULL)
1458d4af9e69SDag-Erling Smørgrav 			strlcpy(component, path, sizeof(component));
1459d4af9e69SDag-Erling Smørgrav 		else {
1460d4af9e69SDag-Erling Smørgrav 			cp++;
1461d4af9e69SDag-Erling Smørgrav 			memcpy(component, path, cp - path);
1462d4af9e69SDag-Erling Smørgrav 			component[cp - path] = '\0';
1463d4af9e69SDag-Erling Smørgrav 		}
1464d4af9e69SDag-Erling Smørgrav 
1465d4af9e69SDag-Erling Smørgrav 		debug3("%s: checking '%s'", __func__, component);
1466d4af9e69SDag-Erling Smørgrav 
1467d4af9e69SDag-Erling Smørgrav 		if (stat(component, &st) != 0)
1468d4af9e69SDag-Erling Smørgrav 			fatal("%s: stat(\"%s\"): %s", __func__,
1469d4af9e69SDag-Erling Smørgrav 			    component, strerror(errno));
1470d4af9e69SDag-Erling Smørgrav 		if (st.st_uid != 0 || (st.st_mode & 022) != 0)
1471d4af9e69SDag-Erling Smørgrav 			fatal("bad ownership or modes for chroot "
1472d4af9e69SDag-Erling Smørgrav 			    "directory %s\"%s\"",
1473d4af9e69SDag-Erling Smørgrav 			    cp == NULL ? "" : "component ", component);
1474d4af9e69SDag-Erling Smørgrav 		if (!S_ISDIR(st.st_mode))
1475d4af9e69SDag-Erling Smørgrav 			fatal("chroot path %s\"%s\" is not a directory",
1476d4af9e69SDag-Erling Smørgrav 			    cp == NULL ? "" : "component ", component);
1477d4af9e69SDag-Erling Smørgrav 
1478d4af9e69SDag-Erling Smørgrav 	}
1479d4af9e69SDag-Erling Smørgrav 
1480d4af9e69SDag-Erling Smørgrav 	if (chdir(path) == -1)
1481d4af9e69SDag-Erling Smørgrav 		fatal("Unable to chdir to chroot path \"%s\": "
1482d4af9e69SDag-Erling Smørgrav 		    "%s", path, strerror(errno));
1483d4af9e69SDag-Erling Smørgrav 	if (chroot(path) == -1)
1484d4af9e69SDag-Erling Smørgrav 		fatal("chroot(\"%s\"): %s", path, strerror(errno));
1485d4af9e69SDag-Erling Smørgrav 	if (chdir("/") == -1)
1486d4af9e69SDag-Erling Smørgrav 		fatal("%s: chdir(/) after chroot: %s",
1487d4af9e69SDag-Erling Smørgrav 		    __func__, strerror(errno));
1488d4af9e69SDag-Erling Smørgrav 	verbose("Changed root directory to \"%s\"", path);
1489d4af9e69SDag-Erling Smørgrav }
1490d4af9e69SDag-Erling Smørgrav 
1491af12a3e7SDag-Erling Smørgrav /* Set login name, uid, gid, and groups. */
1492989dd127SDag-Erling Smørgrav void
149380628bacSDag-Erling Smørgrav do_setusercontext(struct passwd *pw)
1494af12a3e7SDag-Erling Smørgrav {
1495d4af9e69SDag-Erling Smørgrav 	char *chroot_path, *tmp;
1496d4af9e69SDag-Erling Smørgrav 
14974a421b63SDag-Erling Smørgrav 	platform_setusercontext(pw);
1498d4af9e69SDag-Erling Smørgrav 
14994a421b63SDag-Erling Smørgrav 	if (platform_privileged_uidswap()) {
1500989dd127SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1501989dd127SDag-Erling Smørgrav 		if (setusercontext(lc, pw, pw->pw_uid,
1502d4af9e69SDag-Erling Smørgrav 		    (LOGIN_SETALL & ~(LOGIN_SETENV|LOGIN_SETPATH|LOGIN_SETUSER))) < 0) {
1503989dd127SDag-Erling Smørgrav 			perror("unable to set user context");
1504989dd127SDag-Erling Smørgrav 			exit(1);
1505989dd127SDag-Erling Smørgrav 		}
1506989dd127SDag-Erling Smørgrav #else
1507af12a3e7SDag-Erling Smørgrav 		if (setlogin(pw->pw_name) < 0)
1508af12a3e7SDag-Erling Smørgrav 			error("setlogin failed: %s", strerror(errno));
1509af12a3e7SDag-Erling Smørgrav 		if (setgid(pw->pw_gid) < 0) {
1510af12a3e7SDag-Erling Smørgrav 			perror("setgid");
1511af12a3e7SDag-Erling Smørgrav 			exit(1);
1512af12a3e7SDag-Erling Smørgrav 		}
1513af12a3e7SDag-Erling Smørgrav 		/* Initialize the group list. */
1514af12a3e7SDag-Erling Smørgrav 		if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
1515af12a3e7SDag-Erling Smørgrav 			perror("initgroups");
1516af12a3e7SDag-Erling Smørgrav 			exit(1);
1517af12a3e7SDag-Erling Smørgrav 		}
1518af12a3e7SDag-Erling Smørgrav 		endgrent();
1519d4af9e69SDag-Erling Smørgrav #endif
1520b15c8340SDag-Erling Smørgrav 
15214a421b63SDag-Erling Smørgrav 		platform_setusercontext_post_groups(pw);
15228ad9b54aSDag-Erling Smørgrav 
1523d4af9e69SDag-Erling Smørgrav 		if (options.chroot_directory != NULL &&
1524d4af9e69SDag-Erling Smørgrav 		    strcasecmp(options.chroot_directory, "none") != 0) {
1525d4af9e69SDag-Erling Smørgrav                         tmp = tilde_expand_filename(options.chroot_directory,
1526d4af9e69SDag-Erling Smørgrav 			    pw->pw_uid);
1527d4af9e69SDag-Erling Smørgrav 			chroot_path = percent_expand(tmp, "h", pw->pw_dir,
1528d4af9e69SDag-Erling Smørgrav 			    "u", pw->pw_name, (char *)NULL);
1529d4af9e69SDag-Erling Smørgrav 			safely_chroot(chroot_path, pw->pw_uid);
1530d4af9e69SDag-Erling Smørgrav 			free(tmp);
1531d4af9e69SDag-Erling Smørgrav 			free(chroot_path);
1532d4af9e69SDag-Erling Smørgrav 		}
1533d4af9e69SDag-Erling Smørgrav 
1534d4af9e69SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1535d4af9e69SDag-Erling Smørgrav 		if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUSER) < 0) {
1536d4af9e69SDag-Erling Smørgrav 			perror("unable to set user context (setuser)");
1537d4af9e69SDag-Erling Smørgrav 			exit(1);
1538d4af9e69SDag-Erling Smørgrav 		}
15392ec88e9dSDag-Erling Smørgrav 		/*
15402ec88e9dSDag-Erling Smørgrav 		 * FreeBSD's setusercontext() will not apply the user's
15412ec88e9dSDag-Erling Smørgrav 		 * own umask setting unless running with the user's UID.
15422ec88e9dSDag-Erling Smørgrav 		 */
1543*6888a9beSDag-Erling Smørgrav 		(void) setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUMASK);
1544d4af9e69SDag-Erling Smørgrav #else
1545af12a3e7SDag-Erling Smørgrav 		/* Permanently switch to the desired uid. */
1546af12a3e7SDag-Erling Smørgrav 		permanently_set_uid(pw);
1547989dd127SDag-Erling Smørgrav #endif
1548af12a3e7SDag-Erling Smørgrav 	}
1549e73e9afaSDag-Erling Smørgrav 
1550af12a3e7SDag-Erling Smørgrav 	if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
1551af12a3e7SDag-Erling Smørgrav 		fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
155280628bacSDag-Erling Smørgrav }
155380628bacSDag-Erling Smørgrav 
155480628bacSDag-Erling Smørgrav static void
15551ec0d754SDag-Erling Smørgrav do_pwchange(Session *s)
15561ec0d754SDag-Erling Smørgrav {
155721e764dfSDag-Erling Smørgrav 	fflush(NULL);
15581ec0d754SDag-Erling Smørgrav 	fprintf(stderr, "WARNING: Your password has expired.\n");
15591ec0d754SDag-Erling Smørgrav 	if (s->ttyfd != -1) {
15601ec0d754SDag-Erling Smørgrav 		fprintf(stderr,
15611ec0d754SDag-Erling Smørgrav 		    "You must change your password now and login again!\n");
1562e146993eSDag-Erling Smørgrav #ifdef WITH_SELINUX
1563e146993eSDag-Erling Smørgrav 		setexeccon(NULL);
1564e146993eSDag-Erling Smørgrav #endif
1565aa49c926SDag-Erling Smørgrav #ifdef PASSWD_NEEDS_USERNAME
1566aa49c926SDag-Erling Smørgrav 		execl(_PATH_PASSWD_PROG, "passwd", s->pw->pw_name,
1567aa49c926SDag-Erling Smørgrav 		    (char *)NULL);
1568aa49c926SDag-Erling Smørgrav #else
15691ec0d754SDag-Erling Smørgrav 		execl(_PATH_PASSWD_PROG, "passwd", (char *)NULL);
1570aa49c926SDag-Erling Smørgrav #endif
15711ec0d754SDag-Erling Smørgrav 		perror("passwd");
15721ec0d754SDag-Erling Smørgrav 	} else {
15731ec0d754SDag-Erling Smørgrav 		fprintf(stderr,
15741ec0d754SDag-Erling Smørgrav 		    "Password change required but no TTY available.\n");
15751ec0d754SDag-Erling Smørgrav 	}
15761ec0d754SDag-Erling Smørgrav 	exit(1);
15771ec0d754SDag-Erling Smørgrav }
15781ec0d754SDag-Erling Smørgrav 
15791ec0d754SDag-Erling Smørgrav static void
158080628bacSDag-Erling Smørgrav launch_login(struct passwd *pw, const char *hostname)
158180628bacSDag-Erling Smørgrav {
158280628bacSDag-Erling Smørgrav 	/* Launch login(1). */
158380628bacSDag-Erling Smørgrav 
1584989dd127SDag-Erling Smørgrav 	execl(LOGIN_PROGRAM, "login", "-h", hostname,
1585989dd127SDag-Erling Smørgrav #ifdef xxxLOGIN_NEEDS_TERM
1586989dd127SDag-Erling Smørgrav 		    (s->term ? s->term : "unknown"),
1587989dd127SDag-Erling Smørgrav #endif /* LOGIN_NEEDS_TERM */
1588989dd127SDag-Erling Smørgrav #ifdef LOGIN_NO_ENDOPT
1589989dd127SDag-Erling Smørgrav 	    "-p", "-f", pw->pw_name, (char *)NULL);
1590989dd127SDag-Erling Smørgrav #else
159180628bacSDag-Erling Smørgrav 	    "-p", "-f", "--", pw->pw_name, (char *)NULL);
1592989dd127SDag-Erling Smørgrav #endif
159380628bacSDag-Erling Smørgrav 
159480628bacSDag-Erling Smørgrav 	/* Login couldn't be executed, die. */
159580628bacSDag-Erling Smørgrav 
159680628bacSDag-Erling Smørgrav 	perror("login");
159780628bacSDag-Erling Smørgrav 	exit(1);
1598af12a3e7SDag-Erling Smørgrav }
1599af12a3e7SDag-Erling Smørgrav 
16001ec0d754SDag-Erling Smørgrav static void
16011ec0d754SDag-Erling Smørgrav child_close_fds(void)
16021ec0d754SDag-Erling Smørgrav {
16031ec0d754SDag-Erling Smørgrav 	if (packet_get_connection_in() == packet_get_connection_out())
16041ec0d754SDag-Erling Smørgrav 		close(packet_get_connection_in());
16051ec0d754SDag-Erling Smørgrav 	else {
16061ec0d754SDag-Erling Smørgrav 		close(packet_get_connection_in());
16071ec0d754SDag-Erling Smørgrav 		close(packet_get_connection_out());
16081ec0d754SDag-Erling Smørgrav 	}
16091ec0d754SDag-Erling Smørgrav 	/*
16101ec0d754SDag-Erling Smørgrav 	 * Close all descriptors related to channels.  They will still remain
16111ec0d754SDag-Erling Smørgrav 	 * open in the parent.
16121ec0d754SDag-Erling Smørgrav 	 */
16131ec0d754SDag-Erling Smørgrav 	/* XXX better use close-on-exec? -markus */
16141ec0d754SDag-Erling Smørgrav 	channel_close_all();
16151ec0d754SDag-Erling Smørgrav 
16161ec0d754SDag-Erling Smørgrav 	/*
16171ec0d754SDag-Erling Smørgrav 	 * Close any extra file descriptors.  Note that there may still be
16181ec0d754SDag-Erling Smørgrav 	 * descriptors left by system functions.  They will be closed later.
16191ec0d754SDag-Erling Smørgrav 	 */
16201ec0d754SDag-Erling Smørgrav 	endpwent();
16211ec0d754SDag-Erling Smørgrav 
16221ec0d754SDag-Erling Smørgrav 	/*
1623b74df5b2SDag-Erling Smørgrav 	 * Close any extra open file descriptors so that we don't have them
16241ec0d754SDag-Erling Smørgrav 	 * hanging around in clients.  Note that we want to do this after
16251ec0d754SDag-Erling Smørgrav 	 * initgroups, because at least on Solaris 2.3 it leaves file
16261ec0d754SDag-Erling Smørgrav 	 * descriptors open.
16271ec0d754SDag-Erling Smørgrav 	 */
16284a421b63SDag-Erling Smørgrav 	closefrom(STDERR_FILENO + 1);
16291ec0d754SDag-Erling Smørgrav }
16301ec0d754SDag-Erling Smørgrav 
1631af12a3e7SDag-Erling Smørgrav /*
1632af12a3e7SDag-Erling Smørgrav  * Performs common processing for the child, such as setting up the
1633af12a3e7SDag-Erling Smørgrav  * environment, closing extra file descriptors, setting the user and group
1634af12a3e7SDag-Erling Smørgrav  * ids, and executing the command or shell.
1635af12a3e7SDag-Erling Smørgrav  */
1636d4af9e69SDag-Erling Smørgrav #define ARGV_MAX 10
1637af12a3e7SDag-Erling Smørgrav void
1638af12a3e7SDag-Erling Smørgrav do_child(Session *s, const char *command)
1639af12a3e7SDag-Erling Smørgrav {
1640af12a3e7SDag-Erling Smørgrav 	extern char **environ;
1641989dd127SDag-Erling Smørgrav 	char **env;
1642d4af9e69SDag-Erling Smørgrav 	char *argv[ARGV_MAX];
1643af12a3e7SDag-Erling Smørgrav 	const char *shell, *shell0, *hostname = NULL;
1644af12a3e7SDag-Erling Smørgrav 	struct passwd *pw = s->pw;
1645d4af9e69SDag-Erling Smørgrav 	int r = 0;
1646af12a3e7SDag-Erling Smørgrav 
1647af12a3e7SDag-Erling Smørgrav 	/* remove hostkey from the child's memory */
1648af12a3e7SDag-Erling Smørgrav 	destroy_sensitive_data();
1649af12a3e7SDag-Erling Smørgrav 
16501ec0d754SDag-Erling Smørgrav 	/* Force a password change */
16511ec0d754SDag-Erling Smørgrav 	if (s->authctxt->force_pwchange) {
16521ec0d754SDag-Erling Smørgrav 		do_setusercontext(pw);
16531ec0d754SDag-Erling Smørgrav 		child_close_fds();
16541ec0d754SDag-Erling Smørgrav 		do_pwchange(s);
16551ec0d754SDag-Erling Smørgrav 		exit(1);
16561ec0d754SDag-Erling Smørgrav 	}
16571ec0d754SDag-Erling Smørgrav 
1658af12a3e7SDag-Erling Smørgrav 	/* login(1) is only called if we execute the login shell */
1659af12a3e7SDag-Erling Smørgrav 	if (options.use_login && command != NULL)
1660af12a3e7SDag-Erling Smørgrav 		options.use_login = 0;
1661af12a3e7SDag-Erling Smørgrav 
1662f388f5efSDag-Erling Smørgrav #ifdef _UNICOS
1663f388f5efSDag-Erling Smørgrav 	cray_setup(pw->pw_uid, pw->pw_name, command);
1664f388f5efSDag-Erling Smørgrav #endif /* _UNICOS */
1665f388f5efSDag-Erling Smørgrav 
1666af12a3e7SDag-Erling Smørgrav 	/*
1667af12a3e7SDag-Erling Smørgrav 	 * Login(1) does this as well, and it needs uid 0 for the "-h"
1668af12a3e7SDag-Erling Smørgrav 	 * switch, so we let login(1) to this for us.
1669af12a3e7SDag-Erling Smørgrav 	 */
1670af12a3e7SDag-Erling Smørgrav 	if (!options.use_login) {
1671989dd127SDag-Erling Smørgrav #ifdef HAVE_OSF_SIA
1672e73e9afaSDag-Erling Smørgrav 		session_setup_sia(pw, s->ttyfd == -1 ? NULL : s->tty);
1673989dd127SDag-Erling Smørgrav 		if (!check_quietlogin(s, command))
1674989dd127SDag-Erling Smørgrav 			do_motd();
1675989dd127SDag-Erling Smørgrav #else /* HAVE_OSF_SIA */
1676b74df5b2SDag-Erling Smørgrav 		/* When PAM is enabled we rely on it to do the nologin check */
1677b74df5b2SDag-Erling Smørgrav 		if (!options.use_pam)
1678af12a3e7SDag-Erling Smørgrav 			do_nologin(pw);
1679989dd127SDag-Erling Smørgrav 		do_setusercontext(pw);
168021e764dfSDag-Erling Smørgrav 		/*
168121e764dfSDag-Erling Smørgrav 		 * PAM session modules in do_setusercontext may have
168221e764dfSDag-Erling Smørgrav 		 * generated messages, so if this in an interactive
168321e764dfSDag-Erling Smørgrav 		 * login then display them too.
168421e764dfSDag-Erling Smørgrav 		 */
1685aa49c926SDag-Erling Smørgrav 		if (!check_quietlogin(s, command))
168621e764dfSDag-Erling Smørgrav 			display_loginmsg();
1687989dd127SDag-Erling Smørgrav #endif /* HAVE_OSF_SIA */
1688af12a3e7SDag-Erling Smørgrav 	}
1689af12a3e7SDag-Erling Smørgrav 
1690aa49c926SDag-Erling Smørgrav #ifdef USE_PAM
1691aa49c926SDag-Erling Smørgrav 	if (options.use_pam && !options.use_login && !is_pam_session_open()) {
1692aa49c926SDag-Erling Smørgrav 		debug3("PAM session not opened, exiting");
1693aa49c926SDag-Erling Smørgrav 		display_loginmsg();
1694aa49c926SDag-Erling Smørgrav 		exit(254);
1695aa49c926SDag-Erling Smørgrav 	}
1696aa49c926SDag-Erling Smørgrav #endif
1697aa49c926SDag-Erling Smørgrav 
1698af12a3e7SDag-Erling Smørgrav 	/*
1699af12a3e7SDag-Erling Smørgrav 	 * Get the shell from the password data.  An empty shell field is
1700af12a3e7SDag-Erling Smørgrav 	 * legal, and means /bin/sh.
1701af12a3e7SDag-Erling Smørgrav 	 */
1702af12a3e7SDag-Erling Smørgrav 	shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
1703e73e9afaSDag-Erling Smørgrav 
1704e73e9afaSDag-Erling Smørgrav 	/*
1705e73e9afaSDag-Erling Smørgrav 	 * Make sure $SHELL points to the shell from the password file,
1706e73e9afaSDag-Erling Smørgrav 	 * even if shell is overridden from login.conf
1707e73e9afaSDag-Erling Smørgrav 	 */
1708e73e9afaSDag-Erling Smørgrav 	env = do_setup_env(s, shell);
1709e73e9afaSDag-Erling Smørgrav 
1710af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1711af12a3e7SDag-Erling Smørgrav 	shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);
1712af12a3e7SDag-Erling Smørgrav #endif
1713af12a3e7SDag-Erling Smørgrav 
1714af12a3e7SDag-Erling Smørgrav 	/* we have to stash the hostname before we close our socket. */
1715af12a3e7SDag-Erling Smørgrav 	if (options.use_login)
1716af12a3e7SDag-Erling Smørgrav 		hostname = get_remote_name_or_ip(utmp_len,
1717cf2b5f3bSDag-Erling Smørgrav 		    options.use_dns);
1718af12a3e7SDag-Erling Smørgrav 	/*
1719af12a3e7SDag-Erling Smørgrav 	 * Close the connection descriptors; note that this is the child, and
1720af12a3e7SDag-Erling Smørgrav 	 * the server will still have the socket open, and it is important
1721af12a3e7SDag-Erling Smørgrav 	 * that we do not shutdown it.  Note that the descriptors cannot be
1722af12a3e7SDag-Erling Smørgrav 	 * closed before building the environment, as we call
1723af12a3e7SDag-Erling Smørgrav 	 * get_remote_ipaddr there.
1724af12a3e7SDag-Erling Smørgrav 	 */
17251ec0d754SDag-Erling Smørgrav 	child_close_fds();
1726af12a3e7SDag-Erling Smørgrav 
1727af12a3e7SDag-Erling Smørgrav 	/*
1728af12a3e7SDag-Erling Smørgrav 	 * Must take new environment into use so that .ssh/rc,
1729af12a3e7SDag-Erling Smørgrav 	 * /etc/ssh/sshrc and xauth are run in the proper environment.
1730af12a3e7SDag-Erling Smørgrav 	 */
1731af12a3e7SDag-Erling Smørgrav 	environ = env;
1732af12a3e7SDag-Erling Smørgrav 
17331ec0d754SDag-Erling Smørgrav #if defined(KRB5) && defined(USE_AFS)
17341ec0d754SDag-Erling Smørgrav 	/*
17351ec0d754SDag-Erling Smørgrav 	 * At this point, we check to see if AFS is active and if we have
17361ec0d754SDag-Erling Smørgrav 	 * a valid Kerberos 5 TGT. If so, it seems like a good idea to see
17371ec0d754SDag-Erling Smørgrav 	 * if we can (and need to) extend the ticket into an AFS token. If
17381ec0d754SDag-Erling Smørgrav 	 * we don't do this, we run into potential problems if the user's
17391ec0d754SDag-Erling Smørgrav 	 * home directory is in AFS and it's not world-readable.
17401ec0d754SDag-Erling Smørgrav 	 */
17411ec0d754SDag-Erling Smørgrav 
17421ec0d754SDag-Erling Smørgrav 	if (options.kerberos_get_afs_token && k_hasafs() &&
17431ec0d754SDag-Erling Smørgrav 	    (s->authctxt->krb5_ctx != NULL)) {
17441ec0d754SDag-Erling Smørgrav 		char cell[64];
17451ec0d754SDag-Erling Smørgrav 
17461ec0d754SDag-Erling Smørgrav 		debug("Getting AFS token");
17471ec0d754SDag-Erling Smørgrav 
17481ec0d754SDag-Erling Smørgrav 		k_setpag();
17491ec0d754SDag-Erling Smørgrav 
17501ec0d754SDag-Erling Smørgrav 		if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
17511ec0d754SDag-Erling Smørgrav 			krb5_afslog(s->authctxt->krb5_ctx,
17521ec0d754SDag-Erling Smørgrav 			    s->authctxt->krb5_fwd_ccache, cell, NULL);
17531ec0d754SDag-Erling Smørgrav 
17541ec0d754SDag-Erling Smørgrav 		krb5_afslog_home(s->authctxt->krb5_ctx,
17551ec0d754SDag-Erling Smørgrav 		    s->authctxt->krb5_fwd_ccache, NULL, NULL, pw->pw_dir);
17561ec0d754SDag-Erling Smørgrav 	}
17571ec0d754SDag-Erling Smørgrav #endif
17581ec0d754SDag-Erling Smørgrav 
1759b74df5b2SDag-Erling Smørgrav 	/* Change current directory to the user's home directory. */
1760af12a3e7SDag-Erling Smørgrav 	if (chdir(pw->pw_dir) < 0) {
1761d4af9e69SDag-Erling Smørgrav 		/* Suppress missing homedir warning for chroot case */
1762af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1763d4af9e69SDag-Erling Smørgrav 		r = login_getcapbool(lc, "requirehome", 0);
1764af12a3e7SDag-Erling Smørgrav #endif
1765e2f6069cSDag-Erling Smørgrav 		if (r || options.chroot_directory == NULL ||
1766e2f6069cSDag-Erling Smørgrav 		    strcasecmp(options.chroot_directory, "none") == 0)
1767d4af9e69SDag-Erling Smørgrav 			fprintf(stderr, "Could not chdir to home "
1768d4af9e69SDag-Erling Smørgrav 			    "directory %s: %s\n", pw->pw_dir,
1769d4af9e69SDag-Erling Smørgrav 			    strerror(errno));
1770d4af9e69SDag-Erling Smørgrav 		if (r)
1771d4af9e69SDag-Erling Smørgrav 			exit(1);
1772af12a3e7SDag-Erling Smørgrav 	}
1773af12a3e7SDag-Erling Smørgrav 
1774d4af9e69SDag-Erling Smørgrav 	closefrom(STDERR_FILENO + 1);
1775d4af9e69SDag-Erling Smørgrav 
1776af12a3e7SDag-Erling Smørgrav 	if (!options.use_login)
1777af12a3e7SDag-Erling Smørgrav 		do_rc_files(s, shell);
1778af12a3e7SDag-Erling Smørgrav 
1779ca3176e7SBrian Feldman 	/* restore SIGPIPE for child */
1780ca3176e7SBrian Feldman 	signal(SIGPIPE, SIG_DFL);
1781ca3176e7SBrian Feldman 
1782b15c8340SDag-Erling Smørgrav 	if (s->is_subsystem == SUBSYSTEM_INT_SFTP_ERROR) {
1783b15c8340SDag-Erling Smørgrav 		printf("This service allows sftp connections only.\n");
1784b15c8340SDag-Erling Smørgrav 		fflush(NULL);
1785b15c8340SDag-Erling Smørgrav 		exit(1);
1786b15c8340SDag-Erling Smørgrav 	} else if (s->is_subsystem == SUBSYSTEM_INT_SFTP) {
1787d4af9e69SDag-Erling Smørgrav 		extern int optind, optreset;
1788d4af9e69SDag-Erling Smørgrav 		int i;
1789d4af9e69SDag-Erling Smørgrav 		char *p, *args;
1790d4af9e69SDag-Erling Smørgrav 
17917aee6ffeSDag-Erling Smørgrav 		setproctitle("%s@%s", s->pw->pw_name, INTERNAL_SFTP_NAME);
1792cce7d346SDag-Erling Smørgrav 		args = xstrdup(command ? command : "sftp-server");
1793d4af9e69SDag-Erling Smørgrav 		for (i = 0, (p = strtok(args, " ")); p; (p = strtok(NULL, " ")))
1794d4af9e69SDag-Erling Smørgrav 			if (i < ARGV_MAX - 1)
1795d4af9e69SDag-Erling Smørgrav 				argv[i++] = p;
1796d4af9e69SDag-Erling Smørgrav 		argv[i] = NULL;
1797d4af9e69SDag-Erling Smørgrav 		optind = optreset = 1;
1798d4af9e69SDag-Erling Smørgrav 		__progname = argv[0];
1799b15c8340SDag-Erling Smørgrav #ifdef WITH_SELINUX
1800b15c8340SDag-Erling Smørgrav 		ssh_selinux_change_context("sftpd_t");
1801b15c8340SDag-Erling Smørgrav #endif
1802d4af9e69SDag-Erling Smørgrav 		exit(sftp_server_main(i, argv, s->pw));
1803d4af9e69SDag-Erling Smørgrav 	}
1804d4af9e69SDag-Erling Smørgrav 
1805b15c8340SDag-Erling Smørgrav 	fflush(NULL);
1806b15c8340SDag-Erling Smørgrav 
1807af12a3e7SDag-Erling Smørgrav 	if (options.use_login) {
180880628bacSDag-Erling Smørgrav 		launch_login(pw, hostname);
180980628bacSDag-Erling Smørgrav 		/* NEVERREACHED */
1810af12a3e7SDag-Erling Smørgrav 	}
1811af12a3e7SDag-Erling Smørgrav 
1812af12a3e7SDag-Erling Smørgrav 	/* Get the last component of the shell name. */
1813af12a3e7SDag-Erling Smørgrav 	if ((shell0 = strrchr(shell, '/')) != NULL)
1814af12a3e7SDag-Erling Smørgrav 		shell0++;
1815af12a3e7SDag-Erling Smørgrav 	else
1816af12a3e7SDag-Erling Smørgrav 		shell0 = shell;
1817af12a3e7SDag-Erling Smørgrav 
1818a04a10f8SKris Kennaway 	/*
1819a04a10f8SKris Kennaway 	 * If we have no command, execute the shell.  In this case, the shell
1820a04a10f8SKris Kennaway 	 * name to be passed in argv[0] is preceded by '-' to indicate that
1821a04a10f8SKris Kennaway 	 * this is a login shell.
1822a04a10f8SKris Kennaway 	 */
1823a04a10f8SKris Kennaway 	if (!command) {
1824af12a3e7SDag-Erling Smørgrav 		char argv0[256];
1825a04a10f8SKris Kennaway 
1826a04a10f8SKris Kennaway 		/* Start the shell.  Set initial character to '-'. */
1827af12a3e7SDag-Erling Smørgrav 		argv0[0] = '-';
1828af12a3e7SDag-Erling Smørgrav 
1829af12a3e7SDag-Erling Smørgrav 		if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1)
1830af12a3e7SDag-Erling Smørgrav 		    >= sizeof(argv0) - 1) {
1831af12a3e7SDag-Erling Smørgrav 			errno = EINVAL;
1832af12a3e7SDag-Erling Smørgrav 			perror(shell);
1833af12a3e7SDag-Erling Smørgrav 			exit(1);
1834af12a3e7SDag-Erling Smørgrav 		}
1835a04a10f8SKris Kennaway 
1836a04a10f8SKris Kennaway 		/* Execute the shell. */
1837af12a3e7SDag-Erling Smørgrav 		argv[0] = argv0;
1838a04a10f8SKris Kennaway 		argv[1] = NULL;
1839a04a10f8SKris Kennaway 		execve(shell, argv, env);
1840a04a10f8SKris Kennaway 
1841a04a10f8SKris Kennaway 		/* Executing the shell failed. */
1842a04a10f8SKris Kennaway 		perror(shell);
1843a04a10f8SKris Kennaway 		exit(1);
1844a04a10f8SKris Kennaway 	}
1845a04a10f8SKris Kennaway 	/*
1846a04a10f8SKris Kennaway 	 * Execute the command using the user's shell.  This uses the -c
1847a04a10f8SKris Kennaway 	 * option to execute the command.
1848a04a10f8SKris Kennaway 	 */
1849af12a3e7SDag-Erling Smørgrav 	argv[0] = (char *) shell0;
1850a04a10f8SKris Kennaway 	argv[1] = "-c";
1851a04a10f8SKris Kennaway 	argv[2] = (char *) command;
1852a04a10f8SKris Kennaway 	argv[3] = NULL;
1853a04a10f8SKris Kennaway 	execve(shell, argv, env);
1854a04a10f8SKris Kennaway 	perror(shell);
1855a04a10f8SKris Kennaway 	exit(1);
1856a04a10f8SKris Kennaway }
1857a04a10f8SKris Kennaway 
1858d4af9e69SDag-Erling Smørgrav void
1859d4af9e69SDag-Erling Smørgrav session_unused(int id)
1860d4af9e69SDag-Erling Smørgrav {
1861d4af9e69SDag-Erling Smørgrav 	debug3("%s: session id %d unused", __func__, id);
1862d4af9e69SDag-Erling Smørgrav 	if (id >= options.max_sessions ||
1863d4af9e69SDag-Erling Smørgrav 	    id >= sessions_nalloc) {
1864d4af9e69SDag-Erling Smørgrav 		fatal("%s: insane session id %d (max %d nalloc %d)",
1865d4af9e69SDag-Erling Smørgrav 		    __func__, id, options.max_sessions, sessions_nalloc);
1866d4af9e69SDag-Erling Smørgrav 	}
1867d4af9e69SDag-Erling Smørgrav 	bzero(&sessions[id], sizeof(*sessions));
1868d4af9e69SDag-Erling Smørgrav 	sessions[id].self = id;
1869d4af9e69SDag-Erling Smørgrav 	sessions[id].used = 0;
1870d4af9e69SDag-Erling Smørgrav 	sessions[id].chanid = -1;
1871d4af9e69SDag-Erling Smørgrav 	sessions[id].ptyfd = -1;
1872d4af9e69SDag-Erling Smørgrav 	sessions[id].ttyfd = -1;
1873d4af9e69SDag-Erling Smørgrav 	sessions[id].ptymaster = -1;
1874d4af9e69SDag-Erling Smørgrav 	sessions[id].x11_chanids = NULL;
1875d4af9e69SDag-Erling Smørgrav 	sessions[id].next_unused = sessions_first_unused;
1876d4af9e69SDag-Erling Smørgrav 	sessions_first_unused = id;
1877d4af9e69SDag-Erling Smørgrav }
1878d4af9e69SDag-Erling Smørgrav 
1879a04a10f8SKris Kennaway Session *
1880a04a10f8SKris Kennaway session_new(void)
1881a04a10f8SKris Kennaway {
1882d4af9e69SDag-Erling Smørgrav 	Session *s, *tmp;
1883d4af9e69SDag-Erling Smørgrav 
1884d4af9e69SDag-Erling Smørgrav 	if (sessions_first_unused == -1) {
1885d4af9e69SDag-Erling Smørgrav 		if (sessions_nalloc >= options.max_sessions)
1886a04a10f8SKris Kennaway 			return NULL;
1887d4af9e69SDag-Erling Smørgrav 		debug2("%s: allocate (allocated %d max %d)",
1888d4af9e69SDag-Erling Smørgrav 		    __func__, sessions_nalloc, options.max_sessions);
1889d4af9e69SDag-Erling Smørgrav 		tmp = xrealloc(sessions, sessions_nalloc + 1,
1890d4af9e69SDag-Erling Smørgrav 		    sizeof(*sessions));
1891d4af9e69SDag-Erling Smørgrav 		if (tmp == NULL) {
1892d4af9e69SDag-Erling Smørgrav 			error("%s: cannot allocate %d sessions",
1893d4af9e69SDag-Erling Smørgrav 			    __func__, sessions_nalloc + 1);
1894d4af9e69SDag-Erling Smørgrav 			return NULL;
1895d4af9e69SDag-Erling Smørgrav 		}
1896d4af9e69SDag-Erling Smørgrav 		sessions = tmp;
1897d4af9e69SDag-Erling Smørgrav 		session_unused(sessions_nalloc++);
1898d4af9e69SDag-Erling Smørgrav 	}
1899d4af9e69SDag-Erling Smørgrav 
1900d4af9e69SDag-Erling Smørgrav 	if (sessions_first_unused >= sessions_nalloc ||
1901d4af9e69SDag-Erling Smørgrav 	    sessions_first_unused < 0) {
1902d4af9e69SDag-Erling Smørgrav 		fatal("%s: insane first_unused %d max %d nalloc %d",
1903d4af9e69SDag-Erling Smørgrav 		    __func__, sessions_first_unused, options.max_sessions,
1904d4af9e69SDag-Erling Smørgrav 		    sessions_nalloc);
1905d4af9e69SDag-Erling Smørgrav 	}
1906d4af9e69SDag-Erling Smørgrav 
1907d4af9e69SDag-Erling Smørgrav 	s = &sessions[sessions_first_unused];
1908d4af9e69SDag-Erling Smørgrav 	if (s->used) {
1909d4af9e69SDag-Erling Smørgrav 		fatal("%s: session %d already used",
1910d4af9e69SDag-Erling Smørgrav 		    __func__, sessions_first_unused);
1911d4af9e69SDag-Erling Smørgrav 	}
1912d4af9e69SDag-Erling Smørgrav 	sessions_first_unused = s->next_unused;
1913d4af9e69SDag-Erling Smørgrav 	s->used = 1;
1914d4af9e69SDag-Erling Smørgrav 	s->next_unused = -1;
1915d4af9e69SDag-Erling Smørgrav 	debug("session_new: session %d", s->self);
1916d4af9e69SDag-Erling Smørgrav 
1917d4af9e69SDag-Erling Smørgrav 	return s;
1918a04a10f8SKris Kennaway }
1919a04a10f8SKris Kennaway 
1920af12a3e7SDag-Erling Smørgrav static void
1921a04a10f8SKris Kennaway session_dump(void)
1922a04a10f8SKris Kennaway {
1923a04a10f8SKris Kennaway 	int i;
1924d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
1925a04a10f8SKris Kennaway 		Session *s = &sessions[i];
1926d4af9e69SDag-Erling Smørgrav 
1927d4af9e69SDag-Erling Smørgrav 		debug("dump: used %d next_unused %d session %d %p "
1928d4af9e69SDag-Erling Smørgrav 		    "channel %d pid %ld",
1929a04a10f8SKris Kennaway 		    s->used,
1930d4af9e69SDag-Erling Smørgrav 		    s->next_unused,
1931a04a10f8SKris Kennaway 		    s->self,
1932a04a10f8SKris Kennaway 		    s,
1933a04a10f8SKris Kennaway 		    s->chanid,
193480628bacSDag-Erling Smørgrav 		    (long)s->pid);
1935a04a10f8SKris Kennaway 	}
1936a04a10f8SKris Kennaway }
1937a04a10f8SKris Kennaway 
1938a04a10f8SKris Kennaway int
1939af12a3e7SDag-Erling Smørgrav session_open(Authctxt *authctxt, int chanid)
1940a04a10f8SKris Kennaway {
1941a04a10f8SKris Kennaway 	Session *s = session_new();
1942a04a10f8SKris Kennaway 	debug("session_open: channel %d", chanid);
1943a04a10f8SKris Kennaway 	if (s == NULL) {
1944a04a10f8SKris Kennaway 		error("no more sessions");
1945a04a10f8SKris Kennaway 		return 0;
1946a04a10f8SKris Kennaway 	}
1947af12a3e7SDag-Erling Smørgrav 	s->authctxt = authctxt;
1948af12a3e7SDag-Erling Smørgrav 	s->pw = authctxt->pw;
19491ec0d754SDag-Erling Smørgrav 	if (s->pw == NULL || !authctxt->valid)
1950ca3176e7SBrian Feldman 		fatal("no user for session %d", s->self);
1951a04a10f8SKris Kennaway 	debug("session_open: session %d: link with channel %d", s->self, chanid);
1952a04a10f8SKris Kennaway 	s->chanid = chanid;
1953a04a10f8SKris Kennaway 	return 1;
1954a04a10f8SKris Kennaway }
1955a04a10f8SKris Kennaway 
195680628bacSDag-Erling Smørgrav Session *
195780628bacSDag-Erling Smørgrav session_by_tty(char *tty)
195880628bacSDag-Erling Smørgrav {
195980628bacSDag-Erling Smørgrav 	int i;
1960d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
196180628bacSDag-Erling Smørgrav 		Session *s = &sessions[i];
196280628bacSDag-Erling Smørgrav 		if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) {
196380628bacSDag-Erling Smørgrav 			debug("session_by_tty: session %d tty %s", i, tty);
196480628bacSDag-Erling Smørgrav 			return s;
196580628bacSDag-Erling Smørgrav 		}
196680628bacSDag-Erling Smørgrav 	}
196780628bacSDag-Erling Smørgrav 	debug("session_by_tty: unknown tty %.100s", tty);
196880628bacSDag-Erling Smørgrav 	session_dump();
196980628bacSDag-Erling Smørgrav 	return NULL;
197080628bacSDag-Erling Smørgrav }
197180628bacSDag-Erling Smørgrav 
1972af12a3e7SDag-Erling Smørgrav static Session *
1973a04a10f8SKris Kennaway session_by_channel(int id)
1974a04a10f8SKris Kennaway {
1975a04a10f8SKris Kennaway 	int i;
1976d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
1977a04a10f8SKris Kennaway 		Session *s = &sessions[i];
1978a04a10f8SKris Kennaway 		if (s->used && s->chanid == id) {
1979d4af9e69SDag-Erling Smørgrav 			debug("session_by_channel: session %d channel %d",
1980d4af9e69SDag-Erling Smørgrav 			    i, id);
1981a04a10f8SKris Kennaway 			return s;
1982a04a10f8SKris Kennaway 		}
1983a04a10f8SKris Kennaway 	}
1984a04a10f8SKris Kennaway 	debug("session_by_channel: unknown channel %d", id);
1985a04a10f8SKris Kennaway 	session_dump();
1986a04a10f8SKris Kennaway 	return NULL;
1987a04a10f8SKris Kennaway }
1988a04a10f8SKris Kennaway 
1989af12a3e7SDag-Erling Smørgrav static Session *
1990d4ecd108SDag-Erling Smørgrav session_by_x11_channel(int id)
1991d4ecd108SDag-Erling Smørgrav {
1992d4ecd108SDag-Erling Smørgrav 	int i, j;
1993d4ecd108SDag-Erling Smørgrav 
1994d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
1995d4ecd108SDag-Erling Smørgrav 		Session *s = &sessions[i];
1996d4ecd108SDag-Erling Smørgrav 
1997d4ecd108SDag-Erling Smørgrav 		if (s->x11_chanids == NULL || !s->used)
1998d4ecd108SDag-Erling Smørgrav 			continue;
1999d4ecd108SDag-Erling Smørgrav 		for (j = 0; s->x11_chanids[j] != -1; j++) {
2000d4ecd108SDag-Erling Smørgrav 			if (s->x11_chanids[j] == id) {
2001d4ecd108SDag-Erling Smørgrav 				debug("session_by_x11_channel: session %d "
2002d4ecd108SDag-Erling Smørgrav 				    "channel %d", s->self, id);
2003d4ecd108SDag-Erling Smørgrav 				return s;
2004d4ecd108SDag-Erling Smørgrav 			}
2005d4ecd108SDag-Erling Smørgrav 		}
2006d4ecd108SDag-Erling Smørgrav 	}
2007d4ecd108SDag-Erling Smørgrav 	debug("session_by_x11_channel: unknown channel %d", id);
2008d4ecd108SDag-Erling Smørgrav 	session_dump();
2009d4ecd108SDag-Erling Smørgrav 	return NULL;
2010d4ecd108SDag-Erling Smørgrav }
2011d4ecd108SDag-Erling Smørgrav 
2012d4ecd108SDag-Erling Smørgrav static Session *
2013a04a10f8SKris Kennaway session_by_pid(pid_t pid)
2014a04a10f8SKris Kennaway {
2015a04a10f8SKris Kennaway 	int i;
201680628bacSDag-Erling Smørgrav 	debug("session_by_pid: pid %ld", (long)pid);
2017d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
2018a04a10f8SKris Kennaway 		Session *s = &sessions[i];
2019a04a10f8SKris Kennaway 		if (s->used && s->pid == pid)
2020a04a10f8SKris Kennaway 			return s;
2021a04a10f8SKris Kennaway 	}
202280628bacSDag-Erling Smørgrav 	error("session_by_pid: unknown pid %ld", (long)pid);
2023a04a10f8SKris Kennaway 	session_dump();
2024a04a10f8SKris Kennaway 	return NULL;
2025a04a10f8SKris Kennaway }
2026a04a10f8SKris Kennaway 
2027af12a3e7SDag-Erling Smørgrav static int
2028a04a10f8SKris Kennaway session_window_change_req(Session *s)
2029a04a10f8SKris Kennaway {
2030a04a10f8SKris Kennaway 	s->col = packet_get_int();
2031a04a10f8SKris Kennaway 	s->row = packet_get_int();
2032a04a10f8SKris Kennaway 	s->xpixel = packet_get_int();
2033a04a10f8SKris Kennaway 	s->ypixel = packet_get_int();
2034af12a3e7SDag-Erling Smørgrav 	packet_check_eom();
2035a04a10f8SKris Kennaway 	pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
2036a04a10f8SKris Kennaway 	return 1;
2037a04a10f8SKris Kennaway }
2038a04a10f8SKris Kennaway 
2039af12a3e7SDag-Erling Smørgrav static int
2040a04a10f8SKris Kennaway session_pty_req(Session *s)
2041a04a10f8SKris Kennaway {
2042ca3176e7SBrian Feldman 	u_int len;
2043ca3176e7SBrian Feldman 	int n_bytes;
2044a04a10f8SKris Kennaway 
2045af12a3e7SDag-Erling Smørgrav 	if (no_pty_flag) {
2046af12a3e7SDag-Erling Smørgrav 		debug("Allocating a pty not permitted for this authentication.");
2047c2d3a559SKris Kennaway 		return 0;
2048af12a3e7SDag-Erling Smørgrav 	}
2049af12a3e7SDag-Erling Smørgrav 	if (s->ttyfd != -1) {
2050af12a3e7SDag-Erling Smørgrav 		packet_disconnect("Protocol error: you already have a pty.");
2051a04a10f8SKris Kennaway 		return 0;
2052af12a3e7SDag-Erling Smørgrav 	}
2053af12a3e7SDag-Erling Smørgrav 
2054a04a10f8SKris Kennaway 	s->term = packet_get_string(&len);
2055af12a3e7SDag-Erling Smørgrav 
2056af12a3e7SDag-Erling Smørgrav 	if (compat20) {
2057a04a10f8SKris Kennaway 		s->col = packet_get_int();
2058a04a10f8SKris Kennaway 		s->row = packet_get_int();
2059af12a3e7SDag-Erling Smørgrav 	} else {
2060af12a3e7SDag-Erling Smørgrav 		s->row = packet_get_int();
2061af12a3e7SDag-Erling Smørgrav 		s->col = packet_get_int();
2062af12a3e7SDag-Erling Smørgrav 	}
2063a04a10f8SKris Kennaway 	s->xpixel = packet_get_int();
2064a04a10f8SKris Kennaway 	s->ypixel = packet_get_int();
2065a04a10f8SKris Kennaway 
2066a04a10f8SKris Kennaway 	if (strcmp(s->term, "") == 0) {
2067a04a10f8SKris Kennaway 		xfree(s->term);
2068a04a10f8SKris Kennaway 		s->term = NULL;
2069a04a10f8SKris Kennaway 	}
2070af12a3e7SDag-Erling Smørgrav 
2071a04a10f8SKris Kennaway 	/* Allocate a pty and open it. */
2072af12a3e7SDag-Erling Smørgrav 	debug("Allocating pty.");
2073d4af9e69SDag-Erling Smørgrav 	if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty,
2074d4af9e69SDag-Erling Smørgrav 	    sizeof(s->tty)))) {
2075af12a3e7SDag-Erling Smørgrav 		if (s->term)
2076a04a10f8SKris Kennaway 			xfree(s->term);
2077a04a10f8SKris Kennaway 		s->term = NULL;
2078a04a10f8SKris Kennaway 		s->ptyfd = -1;
2079a04a10f8SKris Kennaway 		s->ttyfd = -1;
2080a04a10f8SKris Kennaway 		error("session_pty_req: session %d alloc failed", s->self);
2081a04a10f8SKris Kennaway 		return 0;
2082a04a10f8SKris Kennaway 	}
2083a04a10f8SKris Kennaway 	debug("session_pty_req: session %d alloc %s", s->self, s->tty);
2084af12a3e7SDag-Erling Smørgrav 
2085af12a3e7SDag-Erling Smørgrav 	/* for SSH1 the tty modes length is not given */
2086af12a3e7SDag-Erling Smørgrav 	if (!compat20)
2087af12a3e7SDag-Erling Smørgrav 		n_bytes = packet_remaining();
2088af12a3e7SDag-Erling Smørgrav 	tty_parse_modes(s->ttyfd, &n_bytes);
2089af12a3e7SDag-Erling Smørgrav 
209080628bacSDag-Erling Smørgrav 	if (!use_privsep)
2091a04a10f8SKris Kennaway 		pty_setowner(s->pw, s->tty);
2092af12a3e7SDag-Erling Smørgrav 
2093af12a3e7SDag-Erling Smørgrav 	/* Set window size from the packet. */
2094a04a10f8SKris Kennaway 	pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
2095a04a10f8SKris Kennaway 
2096af12a3e7SDag-Erling Smørgrav 	packet_check_eom();
2097a04a10f8SKris Kennaway 	session_proctitle(s);
2098a04a10f8SKris Kennaway 	return 1;
2099a04a10f8SKris Kennaway }
2100a04a10f8SKris Kennaway 
2101af12a3e7SDag-Erling Smørgrav static int
2102a04a10f8SKris Kennaway session_subsystem_req(Session *s)
2103a04a10f8SKris Kennaway {
2104af12a3e7SDag-Erling Smørgrav 	struct stat st;
2105ca3176e7SBrian Feldman 	u_int len;
2106a04a10f8SKris Kennaway 	int success = 0;
2107333ee039SDag-Erling Smørgrav 	char *prog, *cmd, *subsys = packet_get_string(&len);
2108d4ecd108SDag-Erling Smørgrav 	u_int i;
2109a04a10f8SKris Kennaway 
2110af12a3e7SDag-Erling Smørgrav 	packet_check_eom();
2111e2f6069cSDag-Erling Smørgrav 	logit("subsystem request for %.100s by user %s", subsys,
2112e2f6069cSDag-Erling Smørgrav 	    s->pw->pw_name);
2113a04a10f8SKris Kennaway 
2114c2d3a559SKris Kennaway 	for (i = 0; i < options.num_subsystems; i++) {
2115c2d3a559SKris Kennaway 		if (strcmp(subsys, options.subsystem_name[i]) == 0) {
2116333ee039SDag-Erling Smørgrav 			prog = options.subsystem_command[i];
2117333ee039SDag-Erling Smørgrav 			cmd = options.subsystem_args[i];
2118b15c8340SDag-Erling Smørgrav 			if (strcmp(INTERNAL_SFTP_NAME, prog) == 0) {
2119d4af9e69SDag-Erling Smørgrav 				s->is_subsystem = SUBSYSTEM_INT_SFTP;
2120b15c8340SDag-Erling Smørgrav 				debug("subsystem: %s", prog);
2121d4af9e69SDag-Erling Smørgrav 			} else {
2122b15c8340SDag-Erling Smørgrav 				if (stat(prog, &st) < 0)
2123b15c8340SDag-Erling Smørgrav 					debug("subsystem: cannot stat %s: %s",
2124b15c8340SDag-Erling Smørgrav 					    prog, strerror(errno));
2125d4af9e69SDag-Erling Smørgrav 				s->is_subsystem = SUBSYSTEM_EXT;
2126af12a3e7SDag-Erling Smørgrav 				debug("subsystem: exec() %s", cmd);
2127b15c8340SDag-Erling Smørgrav 			}
2128d4af9e69SDag-Erling Smørgrav 			success = do_exec(s, cmd) == 0;
2129af12a3e7SDag-Erling Smørgrav 			break;
2130c2d3a559SKris Kennaway 		}
2131c2d3a559SKris Kennaway 	}
2132c2d3a559SKris Kennaway 
2133c2d3a559SKris Kennaway 	if (!success)
2134cf2b5f3bSDag-Erling Smørgrav 		logit("subsystem request for %.100s failed, subsystem not found",
2135af12a3e7SDag-Erling Smørgrav 		    subsys);
2136c2d3a559SKris Kennaway 
2137a04a10f8SKris Kennaway 	xfree(subsys);
2138a04a10f8SKris Kennaway 	return success;
2139a04a10f8SKris Kennaway }
2140a04a10f8SKris Kennaway 
2141af12a3e7SDag-Erling Smørgrav static int
2142a04a10f8SKris Kennaway session_x11_req(Session *s)
2143a04a10f8SKris Kennaway {
2144af12a3e7SDag-Erling Smørgrav 	int success;
2145a04a10f8SKris Kennaway 
2146d4ecd108SDag-Erling Smørgrav 	if (s->auth_proto != NULL || s->auth_data != NULL) {
2147d4ecd108SDag-Erling Smørgrav 		error("session_x11_req: session %d: "
2148b74df5b2SDag-Erling Smørgrav 		    "x11 forwarding already active", s->self);
2149d4ecd108SDag-Erling Smørgrav 		return 0;
2150d4ecd108SDag-Erling Smørgrav 	}
2151a04a10f8SKris Kennaway 	s->single_connection = packet_get_char();
2152a04a10f8SKris Kennaway 	s->auth_proto = packet_get_string(NULL);
2153a04a10f8SKris Kennaway 	s->auth_data = packet_get_string(NULL);
2154a04a10f8SKris Kennaway 	s->screen = packet_get_int();
2155af12a3e7SDag-Erling Smørgrav 	packet_check_eom();
2156a04a10f8SKris Kennaway 
2157af12a3e7SDag-Erling Smørgrav 	success = session_setup_x11fwd(s);
2158af12a3e7SDag-Erling Smørgrav 	if (!success) {
2159a04a10f8SKris Kennaway 		xfree(s->auth_proto);
2160a04a10f8SKris Kennaway 		xfree(s->auth_data);
2161af12a3e7SDag-Erling Smørgrav 		s->auth_proto = NULL;
2162af12a3e7SDag-Erling Smørgrav 		s->auth_data = NULL;
2163a04a10f8SKris Kennaway 	}
2164af12a3e7SDag-Erling Smørgrav 	return success;
2165a04a10f8SKris Kennaway }
2166a04a10f8SKris Kennaway 
2167af12a3e7SDag-Erling Smørgrav static int
2168c2d3a559SKris Kennaway session_shell_req(Session *s)
2169c2d3a559SKris Kennaway {
2170af12a3e7SDag-Erling Smørgrav 	packet_check_eom();
2171d4af9e69SDag-Erling Smørgrav 	return do_exec(s, NULL) == 0;
2172c2d3a559SKris Kennaway }
2173c2d3a559SKris Kennaway 
2174af12a3e7SDag-Erling Smørgrav static int
2175c2d3a559SKris Kennaway session_exec_req(Session *s)
2176c2d3a559SKris Kennaway {
2177d4af9e69SDag-Erling Smørgrav 	u_int len, success;
2178d4af9e69SDag-Erling Smørgrav 
2179c2d3a559SKris Kennaway 	char *command = packet_get_string(&len);
2180af12a3e7SDag-Erling Smørgrav 	packet_check_eom();
2181d4af9e69SDag-Erling Smørgrav 	success = do_exec(s, command) == 0;
2182c2d3a559SKris Kennaway 	xfree(command);
2183d4af9e69SDag-Erling Smørgrav 	return success;
2184c2d3a559SKris Kennaway }
2185c2d3a559SKris Kennaway 
2186af12a3e7SDag-Erling Smørgrav static int
2187cf2b5f3bSDag-Erling Smørgrav session_break_req(Session *s)
2188cf2b5f3bSDag-Erling Smørgrav {
2189cf2b5f3bSDag-Erling Smørgrav 
219021e764dfSDag-Erling Smørgrav 	packet_get_int();	/* ignored */
2191cf2b5f3bSDag-Erling Smørgrav 	packet_check_eom();
2192cf2b5f3bSDag-Erling Smørgrav 
2193462c32cbSDag-Erling Smørgrav 	if (s->ptymaster == -1 || tcsendbreak(s->ptymaster, 0) < 0)
2194cf2b5f3bSDag-Erling Smørgrav 		return 0;
2195cf2b5f3bSDag-Erling Smørgrav 	return 1;
2196cf2b5f3bSDag-Erling Smørgrav }
2197cf2b5f3bSDag-Erling Smørgrav 
2198cf2b5f3bSDag-Erling Smørgrav static int
219921e764dfSDag-Erling Smørgrav session_env_req(Session *s)
220021e764dfSDag-Erling Smørgrav {
220121e764dfSDag-Erling Smørgrav 	char *name, *val;
220221e764dfSDag-Erling Smørgrav 	u_int name_len, val_len, i;
220321e764dfSDag-Erling Smørgrav 
220421e764dfSDag-Erling Smørgrav 	name = packet_get_string(&name_len);
220521e764dfSDag-Erling Smørgrav 	val = packet_get_string(&val_len);
220621e764dfSDag-Erling Smørgrav 	packet_check_eom();
220721e764dfSDag-Erling Smørgrav 
220821e764dfSDag-Erling Smørgrav 	/* Don't set too many environment variables */
220921e764dfSDag-Erling Smørgrav 	if (s->num_env > 128) {
221021e764dfSDag-Erling Smørgrav 		debug2("Ignoring env request %s: too many env vars", name);
221121e764dfSDag-Erling Smørgrav 		goto fail;
221221e764dfSDag-Erling Smørgrav 	}
221321e764dfSDag-Erling Smørgrav 
221421e764dfSDag-Erling Smørgrav 	for (i = 0; i < options.num_accept_env; i++) {
221521e764dfSDag-Erling Smørgrav 		if (match_pattern(name, options.accept_env[i])) {
221621e764dfSDag-Erling Smørgrav 			debug2("Setting env %d: %s=%s", s->num_env, name, val);
2217333ee039SDag-Erling Smørgrav 			s->env = xrealloc(s->env, s->num_env + 1,
2218333ee039SDag-Erling Smørgrav 			    sizeof(*s->env));
221921e764dfSDag-Erling Smørgrav 			s->env[s->num_env].name = name;
222021e764dfSDag-Erling Smørgrav 			s->env[s->num_env].val = val;
222121e764dfSDag-Erling Smørgrav 			s->num_env++;
222221e764dfSDag-Erling Smørgrav 			return (1);
222321e764dfSDag-Erling Smørgrav 		}
222421e764dfSDag-Erling Smørgrav 	}
222521e764dfSDag-Erling Smørgrav 	debug2("Ignoring env request %s: disallowed name", name);
222621e764dfSDag-Erling Smørgrav 
222721e764dfSDag-Erling Smørgrav  fail:
222821e764dfSDag-Erling Smørgrav 	xfree(name);
222921e764dfSDag-Erling Smørgrav 	xfree(val);
223021e764dfSDag-Erling Smørgrav 	return (0);
223121e764dfSDag-Erling Smørgrav }
223221e764dfSDag-Erling Smørgrav 
223321e764dfSDag-Erling Smørgrav static int
2234ca3176e7SBrian Feldman session_auth_agent_req(Session *s)
2235ca3176e7SBrian Feldman {
2236ca3176e7SBrian Feldman 	static int called = 0;
2237af12a3e7SDag-Erling Smørgrav 	packet_check_eom();
2238d4af9e69SDag-Erling Smørgrav 	if (no_agent_forwarding_flag || !options.allow_agent_forwarding) {
2239ca3176e7SBrian Feldman 		debug("session_auth_agent_req: no_agent_forwarding_flag");
2240ca3176e7SBrian Feldman 		return 0;
2241ca3176e7SBrian Feldman 	}
2242ca3176e7SBrian Feldman 	if (called) {
2243ca3176e7SBrian Feldman 		return 0;
2244ca3176e7SBrian Feldman 	} else {
2245ca3176e7SBrian Feldman 		called = 1;
2246ca3176e7SBrian Feldman 		return auth_input_request_forwarding(s->pw);
2247ca3176e7SBrian Feldman 	}
2248ca3176e7SBrian Feldman }
2249ca3176e7SBrian Feldman 
2250af12a3e7SDag-Erling Smørgrav int
2251af12a3e7SDag-Erling Smørgrav session_input_channel_req(Channel *c, const char *rtype)
2252a04a10f8SKris Kennaway {
2253a04a10f8SKris Kennaway 	int success = 0;
2254a04a10f8SKris Kennaway 	Session *s;
2255a04a10f8SKris Kennaway 
2256af12a3e7SDag-Erling Smørgrav 	if ((s = session_by_channel(c->self)) == NULL) {
2257cf2b5f3bSDag-Erling Smørgrav 		logit("session_input_channel_req: no session %d req %.100s",
2258af12a3e7SDag-Erling Smørgrav 		    c->self, rtype);
2259af12a3e7SDag-Erling Smørgrav 		return 0;
2260af12a3e7SDag-Erling Smørgrav 	}
2261af12a3e7SDag-Erling Smørgrav 	debug("session_input_channel_req: session %d req %s", s->self, rtype);
2262a04a10f8SKris Kennaway 
2263a04a10f8SKris Kennaway 	/*
2264ca3176e7SBrian Feldman 	 * a session is in LARVAL state until a shell, a command
2265ca3176e7SBrian Feldman 	 * or a subsystem is executed
2266a04a10f8SKris Kennaway 	 */
2267a04a10f8SKris Kennaway 	if (c->type == SSH_CHANNEL_LARVAL) {
2268a04a10f8SKris Kennaway 		if (strcmp(rtype, "shell") == 0) {
2269c2d3a559SKris Kennaway 			success = session_shell_req(s);
2270a04a10f8SKris Kennaway 		} else if (strcmp(rtype, "exec") == 0) {
2271c2d3a559SKris Kennaway 			success = session_exec_req(s);
2272a04a10f8SKris Kennaway 		} else if (strcmp(rtype, "pty-req") == 0) {
2273a04a10f8SKris Kennaway 			success = session_pty_req(s);
2274a04a10f8SKris Kennaway 		} else if (strcmp(rtype, "x11-req") == 0) {
2275a04a10f8SKris Kennaway 			success = session_x11_req(s);
2276ca3176e7SBrian Feldman 		} else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) {
2277ca3176e7SBrian Feldman 			success = session_auth_agent_req(s);
2278a04a10f8SKris Kennaway 		} else if (strcmp(rtype, "subsystem") == 0) {
2279a04a10f8SKris Kennaway 			success = session_subsystem_req(s);
228021e764dfSDag-Erling Smørgrav 		} else if (strcmp(rtype, "env") == 0) {
228121e764dfSDag-Erling Smørgrav 			success = session_env_req(s);
2282a04a10f8SKris Kennaway 		}
2283a04a10f8SKris Kennaway 	}
2284a04a10f8SKris Kennaway 	if (strcmp(rtype, "window-change") == 0) {
2285a04a10f8SKris Kennaway 		success = session_window_change_req(s);
228621e764dfSDag-Erling Smørgrav 	} else if (strcmp(rtype, "break") == 0) {
228721e764dfSDag-Erling Smørgrav 		success = session_break_req(s);
2288a04a10f8SKris Kennaway 	}
228921e764dfSDag-Erling Smørgrav 
2290af12a3e7SDag-Erling Smørgrav 	return success;
2291a04a10f8SKris Kennaway }
2292a04a10f8SKris Kennaway 
2293a04a10f8SKris Kennaway void
2294e2f6069cSDag-Erling Smørgrav session_set_fds(Session *s, int fdin, int fdout, int fderr, int ignore_fderr,
2295e2f6069cSDag-Erling Smørgrav     int is_tty)
2296a04a10f8SKris Kennaway {
2297a04a10f8SKris Kennaway 	if (!compat20)
2298a04a10f8SKris Kennaway 		fatal("session_set_fds: called for proto != 2.0");
2299a04a10f8SKris Kennaway 	/*
2300a04a10f8SKris Kennaway 	 * now that have a child and a pipe to the child,
2301a04a10f8SKris Kennaway 	 * we can activate our channel and register the fd's
2302a04a10f8SKris Kennaway 	 */
2303a04a10f8SKris Kennaway 	if (s->chanid == -1)
2304a04a10f8SKris Kennaway 		fatal("no channel for session %d", s->self);
230589986192SBrooks Davis 	if (options.hpn_disabled)
230689986192SBrooks Davis 		channel_set_fds(s->chanid, fdout, fdin, fderr,
2307e2f6069cSDag-Erling Smørgrav 		    ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
2308d4af9e69SDag-Erling Smørgrav 		    1, is_tty, CHAN_SES_WINDOW_DEFAULT);
230989986192SBrooks Davis 	else
231089986192SBrooks Davis 		channel_set_fds(s->chanid, fdout, fdin, fderr,
231189986192SBrooks Davis 		    ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
231289986192SBrooks Davis 		    1, is_tty, options.hpn_buffer_size);
2313a04a10f8SKris Kennaway }
2314a04a10f8SKris Kennaway 
2315af12a3e7SDag-Erling Smørgrav /*
2316af12a3e7SDag-Erling Smørgrav  * Function to perform pty cleanup. Also called if we get aborted abnormally
2317af12a3e7SDag-Erling Smørgrav  * (e.g., due to a dropped connection).
2318af12a3e7SDag-Erling Smørgrav  */
231980628bacSDag-Erling Smørgrav void
23201ec0d754SDag-Erling Smørgrav session_pty_cleanup2(Session *s)
2321a04a10f8SKris Kennaway {
2322af12a3e7SDag-Erling Smørgrav 	if (s == NULL) {
2323af12a3e7SDag-Erling Smørgrav 		error("session_pty_cleanup: no session");
2324af12a3e7SDag-Erling Smørgrav 		return;
2325af12a3e7SDag-Erling Smørgrav 	}
2326af12a3e7SDag-Erling Smørgrav 	if (s->ttyfd == -1)
2327a04a10f8SKris Kennaway 		return;
2328a04a10f8SKris Kennaway 
2329ca3176e7SBrian Feldman 	debug("session_pty_cleanup: session %d release %s", s->self, s->tty);
2330a04a10f8SKris Kennaway 
2331a04a10f8SKris Kennaway 	/* Record that the user has logged out. */
2332af12a3e7SDag-Erling Smørgrav 	if (s->pid != 0)
2333989dd127SDag-Erling Smørgrav 		record_logout(s->pid, s->tty, s->pw->pw_name);
2334a04a10f8SKris Kennaway 
2335a04a10f8SKris Kennaway 	/* Release the pseudo-tty. */
233680628bacSDag-Erling Smørgrav 	if (getuid() == 0)
2337a04a10f8SKris Kennaway 		pty_release(s->tty);
2338a04a10f8SKris Kennaway 
2339a04a10f8SKris Kennaway 	/*
2340a04a10f8SKris Kennaway 	 * Close the server side of the socket pairs.  We must do this after
2341a04a10f8SKris Kennaway 	 * the pty cleanup, so that another process doesn't get this pty
2342a04a10f8SKris Kennaway 	 * while we're still cleaning up.
2343a04a10f8SKris Kennaway 	 */
2344d4af9e69SDag-Erling Smørgrav 	if (s->ptymaster != -1 && close(s->ptymaster) < 0)
2345d4af9e69SDag-Erling Smørgrav 		error("close(s->ptymaster/%d): %s",
2346d4af9e69SDag-Erling Smørgrav 		    s->ptymaster, strerror(errno));
2347af12a3e7SDag-Erling Smørgrav 
2348af12a3e7SDag-Erling Smørgrav 	/* unlink pty from session */
2349af12a3e7SDag-Erling Smørgrav 	s->ttyfd = -1;
2350a04a10f8SKris Kennaway }
2351a04a10f8SKris Kennaway 
235280628bacSDag-Erling Smørgrav void
23531ec0d754SDag-Erling Smørgrav session_pty_cleanup(Session *s)
235480628bacSDag-Erling Smørgrav {
23551ec0d754SDag-Erling Smørgrav 	PRIVSEP(session_pty_cleanup2(s));
235680628bacSDag-Erling Smørgrav }
235780628bacSDag-Erling Smørgrav 
2358f388f5efSDag-Erling Smørgrav static char *
2359f388f5efSDag-Erling Smørgrav sig2name(int sig)
2360f388f5efSDag-Erling Smørgrav {
2361f388f5efSDag-Erling Smørgrav #define SSH_SIG(x) if (sig == SIG ## x) return #x
2362f388f5efSDag-Erling Smørgrav 	SSH_SIG(ABRT);
2363f388f5efSDag-Erling Smørgrav 	SSH_SIG(ALRM);
2364f388f5efSDag-Erling Smørgrav 	SSH_SIG(FPE);
2365f388f5efSDag-Erling Smørgrav 	SSH_SIG(HUP);
2366f388f5efSDag-Erling Smørgrav 	SSH_SIG(ILL);
2367f388f5efSDag-Erling Smørgrav 	SSH_SIG(INT);
2368f388f5efSDag-Erling Smørgrav 	SSH_SIG(KILL);
2369f388f5efSDag-Erling Smørgrav 	SSH_SIG(PIPE);
2370f388f5efSDag-Erling Smørgrav 	SSH_SIG(QUIT);
2371f388f5efSDag-Erling Smørgrav 	SSH_SIG(SEGV);
2372f388f5efSDag-Erling Smørgrav 	SSH_SIG(TERM);
2373f388f5efSDag-Erling Smørgrav 	SSH_SIG(USR1);
2374f388f5efSDag-Erling Smørgrav 	SSH_SIG(USR2);
2375f388f5efSDag-Erling Smørgrav #undef	SSH_SIG
2376f388f5efSDag-Erling Smørgrav 	return "SIG@openssh.com";
2377f388f5efSDag-Erling Smørgrav }
2378f388f5efSDag-Erling Smørgrav 
2379af12a3e7SDag-Erling Smørgrav static void
2380d4ecd108SDag-Erling Smørgrav session_close_x11(int id)
2381d4ecd108SDag-Erling Smørgrav {
2382d4ecd108SDag-Erling Smørgrav 	Channel *c;
2383d4ecd108SDag-Erling Smørgrav 
2384b74df5b2SDag-Erling Smørgrav 	if ((c = channel_by_id(id)) == NULL) {
2385d4ecd108SDag-Erling Smørgrav 		debug("session_close_x11: x11 channel %d missing", id);
2386d4ecd108SDag-Erling Smørgrav 	} else {
2387d4ecd108SDag-Erling Smørgrav 		/* Detach X11 listener */
2388d4ecd108SDag-Erling Smørgrav 		debug("session_close_x11: detach x11 channel %d", id);
2389d4ecd108SDag-Erling Smørgrav 		channel_cancel_cleanup(id);
2390d4ecd108SDag-Erling Smørgrav 		if (c->ostate != CHAN_OUTPUT_CLOSED)
2391d4ecd108SDag-Erling Smørgrav 			chan_mark_dead(c);
2392d4ecd108SDag-Erling Smørgrav 	}
2393d4ecd108SDag-Erling Smørgrav }
2394d4ecd108SDag-Erling Smørgrav 
2395d4ecd108SDag-Erling Smørgrav static void
2396d4ecd108SDag-Erling Smørgrav session_close_single_x11(int id, void *arg)
2397d4ecd108SDag-Erling Smørgrav {
2398d4ecd108SDag-Erling Smørgrav 	Session *s;
2399d4ecd108SDag-Erling Smørgrav 	u_int i;
2400d4ecd108SDag-Erling Smørgrav 
2401d4ecd108SDag-Erling Smørgrav 	debug3("session_close_single_x11: channel %d", id);
2402d4ecd108SDag-Erling Smørgrav 	channel_cancel_cleanup(id);
2403d4ecd108SDag-Erling Smørgrav 	if ((s = session_by_x11_channel(id)) == NULL)
2404d4ecd108SDag-Erling Smørgrav 		fatal("session_close_single_x11: no x11 channel %d", id);
2405d4ecd108SDag-Erling Smørgrav 	for (i = 0; s->x11_chanids[i] != -1; i++) {
2406d4ecd108SDag-Erling Smørgrav 		debug("session_close_single_x11: session %d: "
2407d4ecd108SDag-Erling Smørgrav 		    "closing channel %d", s->self, s->x11_chanids[i]);
2408d4ecd108SDag-Erling Smørgrav 		/*
2409d4ecd108SDag-Erling Smørgrav 		 * The channel "id" is already closing, but make sure we
2410d4ecd108SDag-Erling Smørgrav 		 * close all of its siblings.
2411d4ecd108SDag-Erling Smørgrav 		 */
2412d4ecd108SDag-Erling Smørgrav 		if (s->x11_chanids[i] != id)
2413d4ecd108SDag-Erling Smørgrav 			session_close_x11(s->x11_chanids[i]);
2414d4ecd108SDag-Erling Smørgrav 	}
2415d4ecd108SDag-Erling Smørgrav 	xfree(s->x11_chanids);
2416d4ecd108SDag-Erling Smørgrav 	s->x11_chanids = NULL;
2417d4ecd108SDag-Erling Smørgrav 	if (s->display) {
2418d4ecd108SDag-Erling Smørgrav 		xfree(s->display);
2419d4ecd108SDag-Erling Smørgrav 		s->display = NULL;
2420d4ecd108SDag-Erling Smørgrav 	}
2421d4ecd108SDag-Erling Smørgrav 	if (s->auth_proto) {
2422d4ecd108SDag-Erling Smørgrav 		xfree(s->auth_proto);
2423d4ecd108SDag-Erling Smørgrav 		s->auth_proto = NULL;
2424d4ecd108SDag-Erling Smørgrav 	}
2425d4ecd108SDag-Erling Smørgrav 	if (s->auth_data) {
2426d4ecd108SDag-Erling Smørgrav 		xfree(s->auth_data);
2427d4ecd108SDag-Erling Smørgrav 		s->auth_data = NULL;
2428d4ecd108SDag-Erling Smørgrav 	}
2429d4ecd108SDag-Erling Smørgrav 	if (s->auth_display) {
2430d4ecd108SDag-Erling Smørgrav 		xfree(s->auth_display);
2431d4ecd108SDag-Erling Smørgrav 		s->auth_display = NULL;
2432d4ecd108SDag-Erling Smørgrav 	}
2433d4ecd108SDag-Erling Smørgrav }
2434d4ecd108SDag-Erling Smørgrav 
2435d4ecd108SDag-Erling Smørgrav static void
2436a04a10f8SKris Kennaway session_exit_message(Session *s, int status)
2437a04a10f8SKris Kennaway {
2438a04a10f8SKris Kennaway 	Channel *c;
2439af12a3e7SDag-Erling Smørgrav 
2440af12a3e7SDag-Erling Smørgrav 	if ((c = channel_lookup(s->chanid)) == NULL)
2441af12a3e7SDag-Erling Smørgrav 		fatal("session_exit_message: session %d: no channel %d",
2442a04a10f8SKris Kennaway 		    s->self, s->chanid);
244380628bacSDag-Erling Smørgrav 	debug("session_exit_message: session %d channel %d pid %ld",
244480628bacSDag-Erling Smørgrav 	    s->self, s->chanid, (long)s->pid);
2445a04a10f8SKris Kennaway 
2446a04a10f8SKris Kennaway 	if (WIFEXITED(status)) {
2447af12a3e7SDag-Erling Smørgrav 		channel_request_start(s->chanid, "exit-status", 0);
2448a04a10f8SKris Kennaway 		packet_put_int(WEXITSTATUS(status));
2449a04a10f8SKris Kennaway 		packet_send();
2450a04a10f8SKris Kennaway 	} else if (WIFSIGNALED(status)) {
2451af12a3e7SDag-Erling Smørgrav 		channel_request_start(s->chanid, "exit-signal", 0);
2452f388f5efSDag-Erling Smørgrav 		packet_put_cstring(sig2name(WTERMSIG(status)));
2453989dd127SDag-Erling Smørgrav #ifdef WCOREDUMP
2454d4af9e69SDag-Erling Smørgrav 		packet_put_char(WCOREDUMP(status)? 1 : 0);
2455989dd127SDag-Erling Smørgrav #else /* WCOREDUMP */
2456989dd127SDag-Erling Smørgrav 		packet_put_char(0);
2457989dd127SDag-Erling Smørgrav #endif /* WCOREDUMP */
2458a04a10f8SKris Kennaway 		packet_put_cstring("");
2459a04a10f8SKris Kennaway 		packet_put_cstring("");
2460a04a10f8SKris Kennaway 		packet_send();
2461a04a10f8SKris Kennaway 	} else {
2462a04a10f8SKris Kennaway 		/* Some weird exit cause.  Just exit. */
2463a04a10f8SKris Kennaway 		packet_disconnect("wait returned status %04x.", status);
2464a04a10f8SKris Kennaway 	}
2465a04a10f8SKris Kennaway 
2466a04a10f8SKris Kennaway 	/* disconnect channel */
2467a04a10f8SKris Kennaway 	debug("session_exit_message: release channel %d", s->chanid);
2468b74df5b2SDag-Erling Smørgrav 
2469b74df5b2SDag-Erling Smørgrav 	/*
2470b74df5b2SDag-Erling Smørgrav 	 * Adjust cleanup callback attachment to send close messages when
2471b74df5b2SDag-Erling Smørgrav 	 * the channel gets EOF. The session will be then be closed
2472b74df5b2SDag-Erling Smørgrav 	 * by session_close_by_channel when the childs close their fds.
2473b74df5b2SDag-Erling Smørgrav 	 */
2474b74df5b2SDag-Erling Smørgrav 	channel_register_cleanup(c->self, session_close_by_channel, 1);
2475b74df5b2SDag-Erling Smørgrav 
2476a04a10f8SKris Kennaway 	/*
2477a04a10f8SKris Kennaway 	 * emulate a write failure with 'chan_write_failed', nobody will be
2478a04a10f8SKris Kennaway 	 * interested in data we write.
2479a04a10f8SKris Kennaway 	 * Note that we must not call 'chan_read_failed', since there could
2480a04a10f8SKris Kennaway 	 * be some more data waiting in the pipe.
2481a04a10f8SKris Kennaway 	 */
2482a04a10f8SKris Kennaway 	if (c->ostate != CHAN_OUTPUT_CLOSED)
2483a04a10f8SKris Kennaway 		chan_write_failed(c);
2484a04a10f8SKris Kennaway }
2485a04a10f8SKris Kennaway 
248680628bacSDag-Erling Smørgrav void
2487af12a3e7SDag-Erling Smørgrav session_close(Session *s)
2488a04a10f8SKris Kennaway {
2489d4ecd108SDag-Erling Smørgrav 	u_int i;
249021e764dfSDag-Erling Smørgrav 
249180628bacSDag-Erling Smørgrav 	debug("session_close: session %d pid %ld", s->self, (long)s->pid);
24921ec0d754SDag-Erling Smørgrav 	if (s->ttyfd != -1)
2493af12a3e7SDag-Erling Smørgrav 		session_pty_cleanup(s);
2494a04a10f8SKris Kennaway 	if (s->term)
2495a04a10f8SKris Kennaway 		xfree(s->term);
2496a04a10f8SKris Kennaway 	if (s->display)
2497a04a10f8SKris Kennaway 		xfree(s->display);
2498d4ecd108SDag-Erling Smørgrav 	if (s->x11_chanids)
2499d4ecd108SDag-Erling Smørgrav 		xfree(s->x11_chanids);
2500af12a3e7SDag-Erling Smørgrav 	if (s->auth_display)
2501af12a3e7SDag-Erling Smørgrav 		xfree(s->auth_display);
2502a04a10f8SKris Kennaway 	if (s->auth_data)
2503a04a10f8SKris Kennaway 		xfree(s->auth_data);
2504a04a10f8SKris Kennaway 	if (s->auth_proto)
2505a04a10f8SKris Kennaway 		xfree(s->auth_proto);
2506333ee039SDag-Erling Smørgrav 	if (s->env != NULL) {
250721e764dfSDag-Erling Smørgrav 		for (i = 0; i < s->num_env; i++) {
250821e764dfSDag-Erling Smørgrav 			xfree(s->env[i].name);
250921e764dfSDag-Erling Smørgrav 			xfree(s->env[i].val);
251021e764dfSDag-Erling Smørgrav 		}
251121e764dfSDag-Erling Smørgrav 		xfree(s->env);
2512333ee039SDag-Erling Smørgrav 	}
2513a04a10f8SKris Kennaway 	session_proctitle(s);
2514d4af9e69SDag-Erling Smørgrav 	session_unused(s->self);
2515a04a10f8SKris Kennaway }
2516a04a10f8SKris Kennaway 
2517a04a10f8SKris Kennaway void
2518a04a10f8SKris Kennaway session_close_by_pid(pid_t pid, int status)
2519a04a10f8SKris Kennaway {
2520a04a10f8SKris Kennaway 	Session *s = session_by_pid(pid);
2521a04a10f8SKris Kennaway 	if (s == NULL) {
252280628bacSDag-Erling Smørgrav 		debug("session_close_by_pid: no session for pid %ld",
252380628bacSDag-Erling Smørgrav 		    (long)pid);
2524a04a10f8SKris Kennaway 		return;
2525a04a10f8SKris Kennaway 	}
2526a04a10f8SKris Kennaway 	if (s->chanid != -1)
2527a04a10f8SKris Kennaway 		session_exit_message(s, status);
2528b74df5b2SDag-Erling Smørgrav 	if (s->ttyfd != -1)
2529b74df5b2SDag-Erling Smørgrav 		session_pty_cleanup(s);
2530333ee039SDag-Erling Smørgrav 	s->pid = 0;
2531a04a10f8SKris Kennaway }
2532a04a10f8SKris Kennaway 
2533a04a10f8SKris Kennaway /*
2534a04a10f8SKris Kennaway  * this is called when a channel dies before
2535a04a10f8SKris Kennaway  * the session 'child' itself dies
2536a04a10f8SKris Kennaway  */
2537a04a10f8SKris Kennaway void
2538a04a10f8SKris Kennaway session_close_by_channel(int id, void *arg)
2539a04a10f8SKris Kennaway {
2540a04a10f8SKris Kennaway 	Session *s = session_by_channel(id);
2541b74df5b2SDag-Erling Smørgrav 	u_int i;
2542d4ecd108SDag-Erling Smørgrav 
2543a04a10f8SKris Kennaway 	if (s == NULL) {
2544af12a3e7SDag-Erling Smørgrav 		debug("session_close_by_channel: no session for id %d", id);
2545a04a10f8SKris Kennaway 		return;
2546a04a10f8SKris Kennaway 	}
254780628bacSDag-Erling Smørgrav 	debug("session_close_by_channel: channel %d child %ld",
254880628bacSDag-Erling Smørgrav 	    id, (long)s->pid);
2549af12a3e7SDag-Erling Smørgrav 	if (s->pid != 0) {
2550af12a3e7SDag-Erling Smørgrav 		debug("session_close_by_channel: channel %d: has child", id);
2551af12a3e7SDag-Erling Smørgrav 		/*
2552af12a3e7SDag-Erling Smørgrav 		 * delay detach of session, but release pty, since
2553af12a3e7SDag-Erling Smørgrav 		 * the fd's to the child are already closed
2554af12a3e7SDag-Erling Smørgrav 		 */
25551ec0d754SDag-Erling Smørgrav 		if (s->ttyfd != -1)
2556af12a3e7SDag-Erling Smørgrav 			session_pty_cleanup(s);
2557af12a3e7SDag-Erling Smørgrav 		return;
2558af12a3e7SDag-Erling Smørgrav 	}
2559af12a3e7SDag-Erling Smørgrav 	/* detach by removing callback */
2560a04a10f8SKris Kennaway 	channel_cancel_cleanup(s->chanid);
2561b74df5b2SDag-Erling Smørgrav 
2562b74df5b2SDag-Erling Smørgrav 	/* Close any X11 listeners associated with this session */
2563b74df5b2SDag-Erling Smørgrav 	if (s->x11_chanids != NULL) {
2564b74df5b2SDag-Erling Smørgrav 		for (i = 0; s->x11_chanids[i] != -1; i++) {
2565b74df5b2SDag-Erling Smørgrav 			session_close_x11(s->x11_chanids[i]);
2566b74df5b2SDag-Erling Smørgrav 			s->x11_chanids[i] = -1;
2567b74df5b2SDag-Erling Smørgrav 		}
2568b74df5b2SDag-Erling Smørgrav 	}
2569b74df5b2SDag-Erling Smørgrav 
2570a04a10f8SKris Kennaway 	s->chanid = -1;
2571a04a10f8SKris Kennaway 	session_close(s);
2572af12a3e7SDag-Erling Smørgrav }
2573af12a3e7SDag-Erling Smørgrav 
2574af12a3e7SDag-Erling Smørgrav void
257580628bacSDag-Erling Smørgrav session_destroy_all(void (*closefunc)(Session *))
2576af12a3e7SDag-Erling Smørgrav {
2577af12a3e7SDag-Erling Smørgrav 	int i;
2578d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
2579af12a3e7SDag-Erling Smørgrav 		Session *s = &sessions[i];
258080628bacSDag-Erling Smørgrav 		if (s->used) {
258180628bacSDag-Erling Smørgrav 			if (closefunc != NULL)
258280628bacSDag-Erling Smørgrav 				closefunc(s);
258380628bacSDag-Erling Smørgrav 			else
2584af12a3e7SDag-Erling Smørgrav 				session_close(s);
2585a04a10f8SKris Kennaway 		}
2586a04a10f8SKris Kennaway 	}
258780628bacSDag-Erling Smørgrav }
2588a04a10f8SKris Kennaway 
2589af12a3e7SDag-Erling Smørgrav static char *
2590a04a10f8SKris Kennaway session_tty_list(void)
2591a04a10f8SKris Kennaway {
2592a04a10f8SKris Kennaway 	static char buf[1024];
2593a04a10f8SKris Kennaway 	int i;
2594e73e9afaSDag-Erling Smørgrav 	char *cp;
2595e73e9afaSDag-Erling Smørgrav 
2596a04a10f8SKris Kennaway 	buf[0] = '\0';
2597d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < sessions_nalloc; i++) {
2598a04a10f8SKris Kennaway 		Session *s = &sessions[i];
2599a04a10f8SKris Kennaway 		if (s->used && s->ttyfd != -1) {
2600e73e9afaSDag-Erling Smørgrav 
2601e73e9afaSDag-Erling Smørgrav 			if (strncmp(s->tty, "/dev/", 5) != 0) {
2602e73e9afaSDag-Erling Smørgrav 				cp = strrchr(s->tty, '/');
2603e73e9afaSDag-Erling Smørgrav 				cp = (cp == NULL) ? s->tty : cp + 1;
2604e73e9afaSDag-Erling Smørgrav 			} else
2605e73e9afaSDag-Erling Smørgrav 				cp = s->tty + 5;
2606e73e9afaSDag-Erling Smørgrav 
2607a04a10f8SKris Kennaway 			if (buf[0] != '\0')
2608a04a10f8SKris Kennaway 				strlcat(buf, ",", sizeof buf);
2609e73e9afaSDag-Erling Smørgrav 			strlcat(buf, cp, sizeof buf);
2610a04a10f8SKris Kennaway 		}
2611a04a10f8SKris Kennaway 	}
2612a04a10f8SKris Kennaway 	if (buf[0] == '\0')
2613a04a10f8SKris Kennaway 		strlcpy(buf, "notty", sizeof buf);
2614a04a10f8SKris Kennaway 	return buf;
2615a04a10f8SKris Kennaway }
2616a04a10f8SKris Kennaway 
2617a04a10f8SKris Kennaway void
2618a04a10f8SKris Kennaway session_proctitle(Session *s)
2619a04a10f8SKris Kennaway {
2620a04a10f8SKris Kennaway 	if (s->pw == NULL)
2621a04a10f8SKris Kennaway 		error("no user for session %d", s->self);
2622a04a10f8SKris Kennaway 	else
2623a04a10f8SKris Kennaway 		setproctitle("%s@%s", s->pw->pw_name, session_tty_list());
2624a04a10f8SKris Kennaway }
2625a04a10f8SKris Kennaway 
2626af12a3e7SDag-Erling Smørgrav int
2627af12a3e7SDag-Erling Smørgrav session_setup_x11fwd(Session *s)
2628af12a3e7SDag-Erling Smørgrav {
2629af12a3e7SDag-Erling Smørgrav 	struct stat st;
2630af12a3e7SDag-Erling Smørgrav 	char display[512], auth_display[512];
2631af12a3e7SDag-Erling Smørgrav 	char hostname[MAXHOSTNAMELEN];
2632d4ecd108SDag-Erling Smørgrav 	u_int i;
2633af12a3e7SDag-Erling Smørgrav 
2634af12a3e7SDag-Erling Smørgrav 	if (no_x11_forwarding_flag) {
2635af12a3e7SDag-Erling Smørgrav 		packet_send_debug("X11 forwarding disabled in user configuration file.");
2636af12a3e7SDag-Erling Smørgrav 		return 0;
2637af12a3e7SDag-Erling Smørgrav 	}
2638af12a3e7SDag-Erling Smørgrav 	if (!options.x11_forwarding) {
2639af12a3e7SDag-Erling Smørgrav 		debug("X11 forwarding disabled in server configuration file.");
2640af12a3e7SDag-Erling Smørgrav 		return 0;
2641af12a3e7SDag-Erling Smørgrav 	}
2642af12a3e7SDag-Erling Smørgrav 	if (!options.xauth_location ||
2643af12a3e7SDag-Erling Smørgrav 	    (stat(options.xauth_location, &st) == -1)) {
2644af12a3e7SDag-Erling Smørgrav 		packet_send_debug("No xauth program; cannot forward with spoofing.");
2645af12a3e7SDag-Erling Smørgrav 		return 0;
2646af12a3e7SDag-Erling Smørgrav 	}
2647af12a3e7SDag-Erling Smørgrav 	if (options.use_login) {
2648af12a3e7SDag-Erling Smørgrav 		packet_send_debug("X11 forwarding disabled; "
2649af12a3e7SDag-Erling Smørgrav 		    "not compatible with UseLogin=yes.");
2650af12a3e7SDag-Erling Smørgrav 		return 0;
2651af12a3e7SDag-Erling Smørgrav 	}
2652af12a3e7SDag-Erling Smørgrav 	if (s->display != NULL) {
2653af12a3e7SDag-Erling Smørgrav 		debug("X11 display already set.");
2654af12a3e7SDag-Erling Smørgrav 		return 0;
2655af12a3e7SDag-Erling Smørgrav 	}
2656a82e551fSDag-Erling Smørgrav 	if (x11_create_display_inet(options.x11_display_offset,
2657a82e551fSDag-Erling Smørgrav 	    options.x11_use_localhost, s->single_connection,
2658d4ecd108SDag-Erling Smørgrav 	    &s->display_number, &s->x11_chanids) == -1) {
2659af12a3e7SDag-Erling Smørgrav 		debug("x11_create_display_inet failed.");
2660af12a3e7SDag-Erling Smørgrav 		return 0;
2661af12a3e7SDag-Erling Smørgrav 	}
2662d4ecd108SDag-Erling Smørgrav 	for (i = 0; s->x11_chanids[i] != -1; i++) {
2663d4ecd108SDag-Erling Smørgrav 		channel_register_cleanup(s->x11_chanids[i],
2664b74df5b2SDag-Erling Smørgrav 		    session_close_single_x11, 0);
2665d4ecd108SDag-Erling Smørgrav 	}
2666af12a3e7SDag-Erling Smørgrav 
2667af12a3e7SDag-Erling Smørgrav 	/* Set up a suitable value for the DISPLAY variable. */
2668af12a3e7SDag-Erling Smørgrav 	if (gethostname(hostname, sizeof(hostname)) < 0)
2669af12a3e7SDag-Erling Smørgrav 		fatal("gethostname: %.100s", strerror(errno));
2670af12a3e7SDag-Erling Smørgrav 	/*
2671af12a3e7SDag-Erling Smørgrav 	 * auth_display must be used as the displayname when the
2672af12a3e7SDag-Erling Smørgrav 	 * authorization entry is added with xauth(1).  This will be
2673af12a3e7SDag-Erling Smørgrav 	 * different than the DISPLAY string for localhost displays.
2674af12a3e7SDag-Erling Smørgrav 	 */
2675af12a3e7SDag-Erling Smørgrav 	if (options.x11_use_localhost) {
2676a82e551fSDag-Erling Smørgrav 		snprintf(display, sizeof display, "localhost:%u.%u",
2677af12a3e7SDag-Erling Smørgrav 		    s->display_number, s->screen);
2678a82e551fSDag-Erling Smørgrav 		snprintf(auth_display, sizeof auth_display, "unix:%u.%u",
2679af12a3e7SDag-Erling Smørgrav 		    s->display_number, s->screen);
2680af12a3e7SDag-Erling Smørgrav 		s->display = xstrdup(display);
2681af12a3e7SDag-Erling Smørgrav 		s->auth_display = xstrdup(auth_display);
2682af12a3e7SDag-Erling Smørgrav 	} else {
2683989dd127SDag-Erling Smørgrav #ifdef IPADDR_IN_DISPLAY
2684989dd127SDag-Erling Smørgrav 		struct hostent *he;
2685989dd127SDag-Erling Smørgrav 		struct in_addr my_addr;
2686989dd127SDag-Erling Smørgrav 
2687989dd127SDag-Erling Smørgrav 		he = gethostbyname(hostname);
2688989dd127SDag-Erling Smørgrav 		if (he == NULL) {
2689989dd127SDag-Erling Smørgrav 			error("Can't get IP address for X11 DISPLAY.");
2690989dd127SDag-Erling Smørgrav 			packet_send_debug("Can't get IP address for X11 DISPLAY.");
2691989dd127SDag-Erling Smørgrav 			return 0;
2692989dd127SDag-Erling Smørgrav 		}
2693989dd127SDag-Erling Smørgrav 		memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr));
2694a82e551fSDag-Erling Smørgrav 		snprintf(display, sizeof display, "%.50s:%u.%u", inet_ntoa(my_addr),
2695989dd127SDag-Erling Smørgrav 		    s->display_number, s->screen);
2696989dd127SDag-Erling Smørgrav #else
2697a82e551fSDag-Erling Smørgrav 		snprintf(display, sizeof display, "%.400s:%u.%u", hostname,
2698af12a3e7SDag-Erling Smørgrav 		    s->display_number, s->screen);
2699989dd127SDag-Erling Smørgrav #endif
2700af12a3e7SDag-Erling Smørgrav 		s->display = xstrdup(display);
2701af12a3e7SDag-Erling Smørgrav 		s->auth_display = xstrdup(display);
2702af12a3e7SDag-Erling Smørgrav 	}
2703af12a3e7SDag-Erling Smørgrav 
2704af12a3e7SDag-Erling Smørgrav 	return 1;
2705af12a3e7SDag-Erling Smørgrav }
2706af12a3e7SDag-Erling Smørgrav 
2707af12a3e7SDag-Erling Smørgrav static void
2708ca3176e7SBrian Feldman do_authenticated2(Authctxt *authctxt)
2709a04a10f8SKris Kennaway {
2710af12a3e7SDag-Erling Smørgrav 	server_loop2(authctxt);
27111ec0d754SDag-Erling Smørgrav }
27121ec0d754SDag-Erling Smørgrav 
27131ec0d754SDag-Erling Smørgrav void
27141ec0d754SDag-Erling Smørgrav do_cleanup(Authctxt *authctxt)
27151ec0d754SDag-Erling Smørgrav {
27161ec0d754SDag-Erling Smørgrav 	static int called = 0;
27171ec0d754SDag-Erling Smørgrav 
27181ec0d754SDag-Erling Smørgrav 	debug("do_cleanup");
27191ec0d754SDag-Erling Smørgrav 
27201ec0d754SDag-Erling Smørgrav 	/* no cleanup if we're in the child for login shell */
27211ec0d754SDag-Erling Smørgrav 	if (is_child)
27221ec0d754SDag-Erling Smørgrav 		return;
27231ec0d754SDag-Erling Smørgrav 
27241ec0d754SDag-Erling Smørgrav 	/* avoid double cleanup */
27251ec0d754SDag-Erling Smørgrav 	if (called)
27261ec0d754SDag-Erling Smørgrav 		return;
27271ec0d754SDag-Erling Smørgrav 	called = 1;
27281ec0d754SDag-Erling Smørgrav 
2729d4af9e69SDag-Erling Smørgrav 	if (authctxt == NULL)
27301ec0d754SDag-Erling Smørgrav 		return;
2731d4af9e69SDag-Erling Smørgrav 
2732d4af9e69SDag-Erling Smørgrav #ifdef USE_PAM
2733d4af9e69SDag-Erling Smørgrav 	if (options.use_pam) {
2734d4af9e69SDag-Erling Smørgrav 		sshpam_cleanup();
2735d4af9e69SDag-Erling Smørgrav 		sshpam_thread_cleanup();
2736d4af9e69SDag-Erling Smørgrav 	}
2737d4af9e69SDag-Erling Smørgrav #endif
2738d4af9e69SDag-Erling Smørgrav 
2739d4af9e69SDag-Erling Smørgrav 	if (!authctxt->authenticated)
2740d4af9e69SDag-Erling Smørgrav 		return;
2741d4af9e69SDag-Erling Smørgrav 
27421ec0d754SDag-Erling Smørgrav #ifdef KRB5
27431ec0d754SDag-Erling Smørgrav 	if (options.kerberos_ticket_cleanup &&
27441ec0d754SDag-Erling Smørgrav 	    authctxt->krb5_ctx)
27451ec0d754SDag-Erling Smørgrav 		krb5_cleanup_proc(authctxt);
2746cf2b5f3bSDag-Erling Smørgrav #endif
27471ec0d754SDag-Erling Smørgrav 
27481ec0d754SDag-Erling Smørgrav #ifdef GSSAPI
27491ec0d754SDag-Erling Smørgrav 	if (compat20 && options.gss_cleanup_creds)
27501ec0d754SDag-Erling Smørgrav 		ssh_gssapi_cleanup_creds();
27511ec0d754SDag-Erling Smørgrav #endif
27521ec0d754SDag-Erling Smørgrav 
27531ec0d754SDag-Erling Smørgrav 	/* remove agent socket */
27541ec0d754SDag-Erling Smørgrav 	auth_sock_cleanup_proc(authctxt->pw);
27551ec0d754SDag-Erling Smørgrav 
27561ec0d754SDag-Erling Smørgrav 	/*
27571ec0d754SDag-Erling Smørgrav 	 * Cleanup ptys/utmp only if privsep is disabled,
27581ec0d754SDag-Erling Smørgrav 	 * or if running in monitor.
27591ec0d754SDag-Erling Smørgrav 	 */
27601ec0d754SDag-Erling Smørgrav 	if (!use_privsep || mm_is_monitor())
27611ec0d754SDag-Erling Smørgrav 		session_destroy_all(session_pty_cleanup2);
2762a04a10f8SKris Kennaway }
2763