xref: /freebsd/crypto/openssh/session.c (revision d4ecd1085791f1e31b106a2546b08647fd6a2a17)
1a04a10f8SKris Kennaway /*
2a04a10f8SKris Kennaway  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
3a04a10f8SKris Kennaway  *                    All rights reserved
4c2d3a559SKris Kennaway  *
5c2d3a559SKris Kennaway  * As far as I am concerned, the code I have written for this software
6c2d3a559SKris Kennaway  * can be used freely for any purpose.  Any derived versions of this
7c2d3a559SKris Kennaway  * software must be clearly marked as such, and if the derived work is
8c2d3a559SKris Kennaway  * incompatible with the protocol description in the RFC file, it must be
9c2d3a559SKris Kennaway  * called by a name other than "ssh" or "Secure Shell".
10c2d3a559SKris Kennaway  *
11a04a10f8SKris Kennaway  * SSH2 support by Markus Friedl.
12af12a3e7SDag-Erling Smørgrav  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
13e8aafc91SKris Kennaway  *
14c2d3a559SKris Kennaway  * Redistribution and use in source and binary forms, with or without
15c2d3a559SKris Kennaway  * modification, are permitted provided that the following conditions
16c2d3a559SKris Kennaway  * are met:
17c2d3a559SKris Kennaway  * 1. Redistributions of source code must retain the above copyright
18c2d3a559SKris Kennaway  *    notice, this list of conditions and the following disclaimer.
19c2d3a559SKris Kennaway  * 2. Redistributions in binary form must reproduce the above copyright
20c2d3a559SKris Kennaway  *    notice, this list of conditions and the following disclaimer in the
21c2d3a559SKris Kennaway  *    documentation and/or other materials provided with the distribution.
22c2d3a559SKris Kennaway  *
23c2d3a559SKris Kennaway  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24c2d3a559SKris Kennaway  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25c2d3a559SKris Kennaway  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26c2d3a559SKris Kennaway  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27c2d3a559SKris Kennaway  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28c2d3a559SKris Kennaway  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29c2d3a559SKris Kennaway  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30c2d3a559SKris Kennaway  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31c2d3a559SKris Kennaway  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32c2d3a559SKris Kennaway  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33a04a10f8SKris Kennaway  */
34a04a10f8SKris Kennaway 
35a04a10f8SKris Kennaway #include "includes.h"
36d4ecd108SDag-Erling Smørgrav RCSID("$OpenBSD: session.c,v 1.186 2005/07/25 11:59:40 markus Exp $");
37c62005fcSDag-Erling Smørgrav RCSID("$FreeBSD$");
38a04a10f8SKris Kennaway 
39a04a10f8SKris Kennaway #include "ssh.h"
40ca3176e7SBrian Feldman #include "ssh1.h"
41ca3176e7SBrian Feldman #include "ssh2.h"
42ca3176e7SBrian Feldman #include "xmalloc.h"
43ca3176e7SBrian Feldman #include "sshpty.h"
44a04a10f8SKris Kennaway #include "packet.h"
45a04a10f8SKris Kennaway #include "buffer.h"
4621e764dfSDag-Erling Smørgrav #include "match.h"
47a04a10f8SKris Kennaway #include "uidswap.h"
48a04a10f8SKris Kennaway #include "compat.h"
49a04a10f8SKris Kennaway #include "channels.h"
50a04a10f8SKris Kennaway #include "bufaux.h"
51a04a10f8SKris Kennaway #include "auth.h"
52c2d3a559SKris Kennaway #include "auth-options.h"
53ca3176e7SBrian Feldman #include "pathnames.h"
54ca3176e7SBrian Feldman #include "log.h"
55ca3176e7SBrian Feldman #include "servconf.h"
56ca3176e7SBrian Feldman #include "sshlogin.h"
57ca3176e7SBrian Feldman #include "serverloop.h"
58ca3176e7SBrian Feldman #include "canohost.h"
59ca3176e7SBrian Feldman #include "session.h"
60d4ecd108SDag-Erling Smørgrav #include "kex.h"
6180628bacSDag-Erling Smørgrav #include "monitor_wrap.h"
62a04a10f8SKris Kennaway 
631ec0d754SDag-Erling Smørgrav #if defined(KRB5) && defined(USE_AFS)
641ec0d754SDag-Erling Smørgrav #include <kafs.h>
651ec0d754SDag-Erling Smørgrav #endif
661ec0d754SDag-Erling Smørgrav 
67cf2b5f3bSDag-Erling Smørgrav #ifdef GSSAPI
68cf2b5f3bSDag-Erling Smørgrav #include "ssh-gss.h"
69c2d3a559SKris Kennaway #endif
70e8aafc91SKris Kennaway 
71a04a10f8SKris Kennaway /* func */
72a04a10f8SKris Kennaway 
73a04a10f8SKris Kennaway Session *session_new(void);
74af12a3e7SDag-Erling Smørgrav void	session_set_fds(Session *, int, int, int);
751ec0d754SDag-Erling Smørgrav void	session_pty_cleanup(Session *);
76af12a3e7SDag-Erling Smørgrav void	session_proctitle(Session *);
77af12a3e7SDag-Erling Smørgrav int	session_setup_x11fwd(Session *);
78af12a3e7SDag-Erling Smørgrav void	do_exec_pty(Session *, const char *);
79af12a3e7SDag-Erling Smørgrav void	do_exec_no_pty(Session *, const char *);
80af12a3e7SDag-Erling Smørgrav void	do_exec(Session *, const char *);
81af12a3e7SDag-Erling Smørgrav void	do_login(Session *, const char *);
82989dd127SDag-Erling Smørgrav #ifdef LOGIN_NEEDS_UTMPX
83989dd127SDag-Erling Smørgrav static void	do_pre_login(Session *s);
84989dd127SDag-Erling Smørgrav #endif
85af12a3e7SDag-Erling Smørgrav void	do_child(Session *, const char *);
86ca3176e7SBrian Feldman void	do_motd(void);
87af12a3e7SDag-Erling Smørgrav int	check_quietlogin(Session *, const char *);
88a04a10f8SKris Kennaway 
89af12a3e7SDag-Erling Smørgrav static void do_authenticated1(Authctxt *);
90af12a3e7SDag-Erling Smørgrav static void do_authenticated2(Authctxt *);
91af12a3e7SDag-Erling Smørgrav 
92af12a3e7SDag-Erling Smørgrav static int session_pty_req(Session *);
93a04a10f8SKris Kennaway 
94a04a10f8SKris Kennaway /* import */
95a04a10f8SKris Kennaway extern ServerOptions options;
96a04a10f8SKris Kennaway extern char *__progname;
97a04a10f8SKris Kennaway extern int log_stderr;
98a04a10f8SKris Kennaway extern int debug_flag;
99ca3176e7SBrian Feldman extern u_int utmp_len;
100c2d3a559SKris Kennaway extern int startup_pipe;
101ca3176e7SBrian Feldman extern void destroy_sensitive_data(void);
102cf2b5f3bSDag-Erling Smørgrav extern Buffer loginmsg;
103a04a10f8SKris Kennaway 
104c2d3a559SKris Kennaway /* original command from peer. */
105af12a3e7SDag-Erling Smørgrav const char *original_command = NULL;
106c2d3a559SKris Kennaway 
107a04a10f8SKris Kennaway /* data */
108a04a10f8SKris Kennaway #define MAX_SESSIONS 10
109a04a10f8SKris Kennaway Session	sessions[MAX_SESSIONS];
110a04a10f8SKris Kennaway 
111c2d3a559SKris Kennaway #ifdef HAVE_LOGIN_CAP
11280628bacSDag-Erling Smørgrav login_cap_t *lc;
113c2d3a559SKris Kennaway #endif
114a04a10f8SKris Kennaway 
1151ec0d754SDag-Erling Smørgrav static int is_child = 0;
1161ec0d754SDag-Erling Smørgrav 
11780628bacSDag-Erling Smørgrav /* Name and directory of socket for authentication agent forwarding. */
11880628bacSDag-Erling Smørgrav static char *auth_sock_name = NULL;
11980628bacSDag-Erling Smørgrav static char *auth_sock_dir = NULL;
12080628bacSDag-Erling Smørgrav 
12180628bacSDag-Erling Smørgrav /* removes the agent forwarding socket */
12280628bacSDag-Erling Smørgrav 
12380628bacSDag-Erling Smørgrav static void
1241ec0d754SDag-Erling Smørgrav auth_sock_cleanup_proc(struct passwd *pw)
12580628bacSDag-Erling Smørgrav {
12680628bacSDag-Erling Smørgrav 	if (auth_sock_name != NULL) {
12780628bacSDag-Erling Smørgrav 		temporarily_use_uid(pw);
12880628bacSDag-Erling Smørgrav 		unlink(auth_sock_name);
12980628bacSDag-Erling Smørgrav 		rmdir(auth_sock_dir);
13080628bacSDag-Erling Smørgrav 		auth_sock_name = NULL;
13180628bacSDag-Erling Smørgrav 		restore_uid();
13280628bacSDag-Erling Smørgrav 	}
13380628bacSDag-Erling Smørgrav }
13480628bacSDag-Erling Smørgrav 
13580628bacSDag-Erling Smørgrav static int
13680628bacSDag-Erling Smørgrav auth_input_request_forwarding(struct passwd * pw)
13780628bacSDag-Erling Smørgrav {
13880628bacSDag-Erling Smørgrav 	Channel *nc;
13980628bacSDag-Erling Smørgrav 	int sock;
14080628bacSDag-Erling Smørgrav 	struct sockaddr_un sunaddr;
14180628bacSDag-Erling Smørgrav 
14280628bacSDag-Erling Smørgrav 	if (auth_sock_name != NULL) {
14380628bacSDag-Erling Smørgrav 		error("authentication forwarding requested twice.");
14480628bacSDag-Erling Smørgrav 		return 0;
14580628bacSDag-Erling Smørgrav 	}
14680628bacSDag-Erling Smørgrav 
14780628bacSDag-Erling Smørgrav 	/* Temporarily drop privileged uid for mkdir/bind. */
14880628bacSDag-Erling Smørgrav 	temporarily_use_uid(pw);
14980628bacSDag-Erling Smørgrav 
15080628bacSDag-Erling Smørgrav 	/* Allocate a buffer for the socket name, and format the name. */
15180628bacSDag-Erling Smørgrav 	auth_sock_name = xmalloc(MAXPATHLEN);
15280628bacSDag-Erling Smørgrav 	auth_sock_dir = xmalloc(MAXPATHLEN);
1531ec0d754SDag-Erling Smørgrav 	strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXXXX", MAXPATHLEN);
15480628bacSDag-Erling Smørgrav 
15580628bacSDag-Erling Smørgrav 	/* Create private directory for socket */
15680628bacSDag-Erling Smørgrav 	if (mkdtemp(auth_sock_dir) == NULL) {
15780628bacSDag-Erling Smørgrav 		packet_send_debug("Agent forwarding disabled: "
15880628bacSDag-Erling Smørgrav 		    "mkdtemp() failed: %.100s", strerror(errno));
15980628bacSDag-Erling Smørgrav 		restore_uid();
16080628bacSDag-Erling Smørgrav 		xfree(auth_sock_name);
16180628bacSDag-Erling Smørgrav 		xfree(auth_sock_dir);
16280628bacSDag-Erling Smørgrav 		auth_sock_name = NULL;
16380628bacSDag-Erling Smørgrav 		auth_sock_dir = NULL;
16480628bacSDag-Erling Smørgrav 		return 0;
16580628bacSDag-Erling Smørgrav 	}
16680628bacSDag-Erling Smørgrav 	snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld",
16780628bacSDag-Erling Smørgrav 		 auth_sock_dir, (long) getpid());
16880628bacSDag-Erling Smørgrav 
16980628bacSDag-Erling Smørgrav 	/* Create the socket. */
17080628bacSDag-Erling Smørgrav 	sock = socket(AF_UNIX, SOCK_STREAM, 0);
17180628bacSDag-Erling Smørgrav 	if (sock < 0)
17280628bacSDag-Erling Smørgrav 		packet_disconnect("socket: %.100s", strerror(errno));
17380628bacSDag-Erling Smørgrav 
17480628bacSDag-Erling Smørgrav 	/* Bind it to the name. */
17580628bacSDag-Erling Smørgrav 	memset(&sunaddr, 0, sizeof(sunaddr));
17680628bacSDag-Erling Smørgrav 	sunaddr.sun_family = AF_UNIX;
17780628bacSDag-Erling Smørgrav 	strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path));
17880628bacSDag-Erling Smørgrav 
17980628bacSDag-Erling Smørgrav 	if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0)
18080628bacSDag-Erling Smørgrav 		packet_disconnect("bind: %.100s", strerror(errno));
18180628bacSDag-Erling Smørgrav 
18280628bacSDag-Erling Smørgrav 	/* Restore the privileged uid. */
18380628bacSDag-Erling Smørgrav 	restore_uid();
18480628bacSDag-Erling Smørgrav 
18580628bacSDag-Erling Smørgrav 	/* Start listening on the socket. */
1861ec0d754SDag-Erling Smørgrav 	if (listen(sock, SSH_LISTEN_BACKLOG) < 0)
18780628bacSDag-Erling Smørgrav 		packet_disconnect("listen: %.100s", strerror(errno));
18880628bacSDag-Erling Smørgrav 
18980628bacSDag-Erling Smørgrav 	/* Allocate a channel for the authentication agent socket. */
19080628bacSDag-Erling Smørgrav 	nc = channel_new("auth socket",
19180628bacSDag-Erling Smørgrav 	    SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,
19280628bacSDag-Erling Smørgrav 	    CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
193cf2b5f3bSDag-Erling Smørgrav 	    0, "auth socket", 1);
19480628bacSDag-Erling Smørgrav 	strlcpy(nc->path, auth_sock_name, sizeof(nc->path));
19580628bacSDag-Erling Smørgrav 	return 1;
19680628bacSDag-Erling Smørgrav }
19780628bacSDag-Erling Smørgrav 
1981ec0d754SDag-Erling Smørgrav static void
1991ec0d754SDag-Erling Smørgrav display_loginmsg(void)
2001ec0d754SDag-Erling Smørgrav {
2011ec0d754SDag-Erling Smørgrav 	if (buffer_len(&loginmsg) > 0) {
2021ec0d754SDag-Erling Smørgrav 		buffer_append(&loginmsg, "\0", 1);
20321e764dfSDag-Erling Smørgrav 		printf("%s", (char *)buffer_ptr(&loginmsg));
2041ec0d754SDag-Erling Smørgrav 		buffer_clear(&loginmsg);
2051ec0d754SDag-Erling Smørgrav 	}
2061ec0d754SDag-Erling Smørgrav }
20780628bacSDag-Erling Smørgrav 
208ca3176e7SBrian Feldman void
209ca3176e7SBrian Feldman do_authenticated(Authctxt *authctxt)
210ca3176e7SBrian Feldman {
211e73e9afaSDag-Erling Smørgrav 	setproctitle("%s", authctxt->pw->pw_name);
212e73e9afaSDag-Erling Smørgrav 
213ca3176e7SBrian Feldman 	/*
214ca3176e7SBrian Feldman 	 * Cancel the alarm we set to limit the time taken for
215ca3176e7SBrian Feldman 	 * authentication.
216ca3176e7SBrian Feldman 	 */
217ca3176e7SBrian Feldman 	alarm(0);
218ca3176e7SBrian Feldman 	if (startup_pipe != -1) {
219ca3176e7SBrian Feldman 		close(startup_pipe);
220ca3176e7SBrian Feldman 		startup_pipe = -1;
221ca3176e7SBrian Feldman 	}
222ca3176e7SBrian Feldman 	/* setup the channel layer */
223ca3176e7SBrian Feldman 	if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
224ca3176e7SBrian Feldman 		channel_permit_all_opens();
225ca3176e7SBrian Feldman 
226ca3176e7SBrian Feldman 	if (compat20)
227ca3176e7SBrian Feldman 		do_authenticated2(authctxt);
228ca3176e7SBrian Feldman 	else
229ca3176e7SBrian Feldman 		do_authenticated1(authctxt);
230e9fd63dfSBrian Feldman 
2311ec0d754SDag-Erling Smørgrav 	do_cleanup(authctxt);
232a04a10f8SKris Kennaway }
233a04a10f8SKris Kennaway 
234a04a10f8SKris Kennaway /*
235a04a10f8SKris Kennaway  * Prepares for an interactive session.  This is called after the user has
236a04a10f8SKris Kennaway  * been successfully authenticated.  During this message exchange, pseudo
237a04a10f8SKris Kennaway  * terminals are allocated, X11, TCP/IP, and authentication agent forwardings
238a04a10f8SKris Kennaway  * are requested, etc.
239a04a10f8SKris Kennaway  */
240af12a3e7SDag-Erling Smørgrav static void
241ca3176e7SBrian Feldman do_authenticated1(Authctxt *authctxt)
242a04a10f8SKris Kennaway {
243a04a10f8SKris Kennaway 	Session *s;
244a04a10f8SKris Kennaway 	char *command;
245af12a3e7SDag-Erling Smørgrav 	int success, type, screen_flag;
246a82e551fSDag-Erling Smørgrav 	int enable_compression_after_reply = 0;
247a82e551fSDag-Erling Smørgrav 	u_int proto_len, data_len, dlen, compression_level = 0;
248a04a10f8SKris Kennaway 
249a04a10f8SKris Kennaway 	s = session_new();
250aa49c926SDag-Erling Smørgrav 	if (s == NULL) {
251aa49c926SDag-Erling Smørgrav 		error("no more sessions");
252aa49c926SDag-Erling Smørgrav 		return;
253aa49c926SDag-Erling Smørgrav 	}
254af12a3e7SDag-Erling Smørgrav 	s->authctxt = authctxt;
255ca3176e7SBrian Feldman 	s->pw = authctxt->pw;
256c2d3a559SKris Kennaway 
257a04a10f8SKris Kennaway 	/*
258a04a10f8SKris Kennaway 	 * We stay in this loop until the client requests to execute a shell
259a04a10f8SKris Kennaway 	 * or a command.
260a04a10f8SKris Kennaway 	 */
261a04a10f8SKris Kennaway 	for (;;) {
262ca3176e7SBrian Feldman 		success = 0;
263a04a10f8SKris Kennaway 
264a04a10f8SKris Kennaway 		/* Get a packet from the client. */
265af12a3e7SDag-Erling Smørgrav 		type = packet_read();
266a04a10f8SKris Kennaway 
267a04a10f8SKris Kennaway 		/* Process the packet. */
268a04a10f8SKris Kennaway 		switch (type) {
269a04a10f8SKris Kennaway 		case SSH_CMSG_REQUEST_COMPRESSION:
270a04a10f8SKris Kennaway 			compression_level = packet_get_int();
271af12a3e7SDag-Erling Smørgrav 			packet_check_eom();
272a04a10f8SKris Kennaway 			if (compression_level < 1 || compression_level > 9) {
27321e764dfSDag-Erling Smørgrav 				packet_send_debug("Received invalid compression level %d.",
274a04a10f8SKris Kennaway 				    compression_level);
275a04a10f8SKris Kennaway 				break;
276a04a10f8SKris Kennaway 			}
277d4ecd108SDag-Erling Smørgrav 			if (options.compression == COMP_NONE) {
27880628bacSDag-Erling Smørgrav 				debug2("compression disabled");
27980628bacSDag-Erling Smørgrav 				break;
28080628bacSDag-Erling Smørgrav 			}
281a04a10f8SKris Kennaway 			/* Enable compression after we have responded with SUCCESS. */
282a04a10f8SKris Kennaway 			enable_compression_after_reply = 1;
283a04a10f8SKris Kennaway 			success = 1;
284a04a10f8SKris Kennaway 			break;
285a04a10f8SKris Kennaway 
286a04a10f8SKris Kennaway 		case SSH_CMSG_REQUEST_PTY:
287af12a3e7SDag-Erling Smørgrav 			success = session_pty_req(s);
288a04a10f8SKris Kennaway 			break;
289a04a10f8SKris Kennaway 
290a04a10f8SKris Kennaway 		case SSH_CMSG_X11_REQUEST_FORWARDING:
291a04a10f8SKris Kennaway 			s->auth_proto = packet_get_string(&proto_len);
292a04a10f8SKris Kennaway 			s->auth_data = packet_get_string(&data_len);
293a04a10f8SKris Kennaway 
294ca3176e7SBrian Feldman 			screen_flag = packet_get_protocol_flags() &
295ca3176e7SBrian Feldman 			    SSH_PROTOFLAG_SCREEN_NUMBER;
296ca3176e7SBrian Feldman 			debug2("SSH_PROTOFLAG_SCREEN_NUMBER: %d", screen_flag);
297ca3176e7SBrian Feldman 
298ca3176e7SBrian Feldman 			if (packet_remaining() == 4) {
299ca3176e7SBrian Feldman 				if (!screen_flag)
300ca3176e7SBrian Feldman 					debug2("Buggy client: "
301ca3176e7SBrian Feldman 					    "X11 screen flag missing");
302a04a10f8SKris Kennaway 				s->screen = packet_get_int();
303ca3176e7SBrian Feldman 			} else {
304a04a10f8SKris Kennaway 				s->screen = 0;
305ca3176e7SBrian Feldman 			}
306af12a3e7SDag-Erling Smørgrav 			packet_check_eom();
307af12a3e7SDag-Erling Smørgrav 			success = session_setup_x11fwd(s);
308af12a3e7SDag-Erling Smørgrav 			if (!success) {
309af12a3e7SDag-Erling Smørgrav 				xfree(s->auth_proto);
310af12a3e7SDag-Erling Smørgrav 				xfree(s->auth_data);
311af12a3e7SDag-Erling Smørgrav 				s->auth_proto = NULL;
312af12a3e7SDag-Erling Smørgrav 				s->auth_data = NULL;
313a04a10f8SKris Kennaway 			}
314a04a10f8SKris Kennaway 			break;
315a04a10f8SKris Kennaway 
316a04a10f8SKris Kennaway 		case SSH_CMSG_AGENT_REQUEST_FORWARDING:
317a04a10f8SKris Kennaway 			if (no_agent_forwarding_flag || compat13) {
318a04a10f8SKris Kennaway 				debug("Authentication agent forwarding not permitted for this authentication.");
319a04a10f8SKris Kennaway 				break;
320a04a10f8SKris Kennaway 			}
321a04a10f8SKris Kennaway 			debug("Received authentication agent forwarding request.");
322ca3176e7SBrian Feldman 			success = auth_input_request_forwarding(s->pw);
323a04a10f8SKris Kennaway 			break;
324a04a10f8SKris Kennaway 
325a04a10f8SKris Kennaway 		case SSH_CMSG_PORT_FORWARD_REQUEST:
326a04a10f8SKris Kennaway 			if (no_port_forwarding_flag) {
327a04a10f8SKris Kennaway 				debug("Port forwarding not permitted for this authentication.");
328a04a10f8SKris Kennaway 				break;
329a04a10f8SKris Kennaway 			}
33009958426SBrian Feldman 			if (!options.allow_tcp_forwarding) {
33109958426SBrian Feldman 				debug("Port forwarding not permitted.");
33209958426SBrian Feldman 				break;
33309958426SBrian Feldman 			}
334a04a10f8SKris Kennaway 			debug("Received TCP/IP port forwarding request.");
335ca3176e7SBrian Feldman 			channel_input_port_forward_request(s->pw->pw_uid == 0, options.gateway_ports);
336a04a10f8SKris Kennaway 			success = 1;
337a04a10f8SKris Kennaway 			break;
338a04a10f8SKris Kennaway 
339a04a10f8SKris Kennaway 		case SSH_CMSG_MAX_PACKET_SIZE:
340a04a10f8SKris Kennaway 			if (packet_set_maxsize(packet_get_int()) > 0)
341a04a10f8SKris Kennaway 				success = 1;
342a04a10f8SKris Kennaway 			break;
343a04a10f8SKris Kennaway 
344a04a10f8SKris Kennaway 		case SSH_CMSG_EXEC_SHELL:
345a04a10f8SKris Kennaway 		case SSH_CMSG_EXEC_CMD:
346a04a10f8SKris Kennaway 			if (type == SSH_CMSG_EXEC_CMD) {
347a04a10f8SKris Kennaway 				command = packet_get_string(&dlen);
348a04a10f8SKris Kennaway 				debug("Exec command '%.500s'", command);
349af12a3e7SDag-Erling Smørgrav 				do_exec(s, command);
350a04a10f8SKris Kennaway 				xfree(command);
351af12a3e7SDag-Erling Smørgrav 			} else {
352af12a3e7SDag-Erling Smørgrav 				do_exec(s, NULL);
353af12a3e7SDag-Erling Smørgrav 			}
354af12a3e7SDag-Erling Smørgrav 			packet_check_eom();
355af12a3e7SDag-Erling Smørgrav 			session_close(s);
356a04a10f8SKris Kennaway 			return;
357a04a10f8SKris Kennaway 
358a04a10f8SKris Kennaway 		default:
359a04a10f8SKris Kennaway 			/*
360a04a10f8SKris Kennaway 			 * Any unknown messages in this phase are ignored,
361a04a10f8SKris Kennaway 			 * and a failure message is returned.
362a04a10f8SKris Kennaway 			 */
363cf2b5f3bSDag-Erling Smørgrav 			logit("Unknown packet type received after authentication: %d", type);
364a04a10f8SKris Kennaway 		}
365a04a10f8SKris Kennaway 		packet_start(success ? SSH_SMSG_SUCCESS : SSH_SMSG_FAILURE);
366a04a10f8SKris Kennaway 		packet_send();
367a04a10f8SKris Kennaway 		packet_write_wait();
368a04a10f8SKris Kennaway 
369a04a10f8SKris Kennaway 		/* Enable compression now that we have replied if appropriate. */
370a04a10f8SKris Kennaway 		if (enable_compression_after_reply) {
371a04a10f8SKris Kennaway 			enable_compression_after_reply = 0;
372a04a10f8SKris Kennaway 			packet_start_compression(compression_level);
373a04a10f8SKris Kennaway 		}
374a04a10f8SKris Kennaway 	}
375a04a10f8SKris Kennaway }
376a04a10f8SKris Kennaway 
377a04a10f8SKris Kennaway /*
378a04a10f8SKris Kennaway  * This is called to fork and execute a command when we have no tty.  This
379a04a10f8SKris Kennaway  * will call do_child from the child, and server_loop from the parent after
380a04a10f8SKris Kennaway  * setting up file descriptors and such.
381a04a10f8SKris Kennaway  */
382a04a10f8SKris Kennaway void
383ca3176e7SBrian Feldman do_exec_no_pty(Session *s, const char *command)
384a04a10f8SKris Kennaway {
38580628bacSDag-Erling Smørgrav 	pid_t pid;
386a04a10f8SKris Kennaway 
387a04a10f8SKris Kennaway #ifdef USE_PIPES
388a04a10f8SKris Kennaway 	int pin[2], pout[2], perr[2];
389a04a10f8SKris Kennaway 	/* Allocate pipes for communicating with the program. */
390a04a10f8SKris Kennaway 	if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0)
391a04a10f8SKris Kennaway 		packet_disconnect("Could not create pipes: %.100s",
392a04a10f8SKris Kennaway 				  strerror(errno));
393a04a10f8SKris Kennaway #else /* USE_PIPES */
394a04a10f8SKris Kennaway 	int inout[2], err[2];
395a04a10f8SKris Kennaway 	/* Uses socket pairs to communicate with the program. */
396a04a10f8SKris Kennaway 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 ||
397a04a10f8SKris Kennaway 	    socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0)
398a04a10f8SKris Kennaway 		packet_disconnect("Could not create socket pairs: %.100s",
399a04a10f8SKris Kennaway 				  strerror(errno));
400a04a10f8SKris Kennaway #endif /* USE_PIPES */
401a04a10f8SKris Kennaway 	if (s == NULL)
402a04a10f8SKris Kennaway 		fatal("do_exec_no_pty: no session");
403a04a10f8SKris Kennaway 
404a04a10f8SKris Kennaway 	session_proctitle(s);
405a04a10f8SKris Kennaway 
406989dd127SDag-Erling Smørgrav #if defined(USE_PAM)
4071ec0d754SDag-Erling Smørgrav 	if (options.use_pam && !use_privsep)
408989dd127SDag-Erling Smørgrav 		do_pam_setcred(1);
40909958426SBrian Feldman #endif /* USE_PAM */
41009958426SBrian Feldman 
411a04a10f8SKris Kennaway 	/* Fork the child. */
412a04a10f8SKris Kennaway 	if ((pid = fork()) == 0) {
4131ec0d754SDag-Erling Smørgrav 		is_child = 1;
414f388f5efSDag-Erling Smørgrav 
415a04a10f8SKris Kennaway 		/* Child.  Reinitialize the log since the pid has changed. */
416a04a10f8SKris Kennaway 		log_init(__progname, options.log_level, options.log_facility, log_stderr);
417a04a10f8SKris Kennaway 
418a04a10f8SKris Kennaway 		/*
419a04a10f8SKris Kennaway 		 * Create a new session and process group since the 4.4BSD
420a04a10f8SKris Kennaway 		 * setlogin() affects the entire process group.
421a04a10f8SKris Kennaway 		 */
422a04a10f8SKris Kennaway 		if (setsid() < 0)
423a04a10f8SKris Kennaway 			error("setsid failed: %.100s", strerror(errno));
424a04a10f8SKris Kennaway 
425a04a10f8SKris Kennaway #ifdef USE_PIPES
426a04a10f8SKris Kennaway 		/*
427a04a10f8SKris Kennaway 		 * Redirect stdin.  We close the parent side of the socket
428a04a10f8SKris Kennaway 		 * pair, and make the child side the standard input.
429a04a10f8SKris Kennaway 		 */
430a04a10f8SKris Kennaway 		close(pin[1]);
431a04a10f8SKris Kennaway 		if (dup2(pin[0], 0) < 0)
432a04a10f8SKris Kennaway 			perror("dup2 stdin");
433a04a10f8SKris Kennaway 		close(pin[0]);
434a04a10f8SKris Kennaway 
435a04a10f8SKris Kennaway 		/* Redirect stdout. */
436a04a10f8SKris Kennaway 		close(pout[0]);
437a04a10f8SKris Kennaway 		if (dup2(pout[1], 1) < 0)
438a04a10f8SKris Kennaway 			perror("dup2 stdout");
439a04a10f8SKris Kennaway 		close(pout[1]);
440a04a10f8SKris Kennaway 
441a04a10f8SKris Kennaway 		/* Redirect stderr. */
442a04a10f8SKris Kennaway 		close(perr[0]);
443a04a10f8SKris Kennaway 		if (dup2(perr[1], 2) < 0)
444a04a10f8SKris Kennaway 			perror("dup2 stderr");
445a04a10f8SKris Kennaway 		close(perr[1]);
446a04a10f8SKris Kennaway #else /* USE_PIPES */
447a04a10f8SKris Kennaway 		/*
448a04a10f8SKris Kennaway 		 * Redirect stdin, stdout, and stderr.  Stdin and stdout will
449a04a10f8SKris Kennaway 		 * use the same socket, as some programs (particularly rdist)
450a04a10f8SKris Kennaway 		 * seem to depend on it.
451a04a10f8SKris Kennaway 		 */
452a04a10f8SKris Kennaway 		close(inout[1]);
453a04a10f8SKris Kennaway 		close(err[1]);
454a04a10f8SKris Kennaway 		if (dup2(inout[0], 0) < 0)	/* stdin */
455a04a10f8SKris Kennaway 			perror("dup2 stdin");
456a04a10f8SKris Kennaway 		if (dup2(inout[0], 1) < 0)	/* stdout.  Note: same socket as stdin. */
457a04a10f8SKris Kennaway 			perror("dup2 stdout");
458a04a10f8SKris Kennaway 		if (dup2(err[0], 2) < 0)	/* stderr */
459a04a10f8SKris Kennaway 			perror("dup2 stderr");
460a04a10f8SKris Kennaway #endif /* USE_PIPES */
461a04a10f8SKris Kennaway 
462f388f5efSDag-Erling Smørgrav #ifdef _UNICOS
463f388f5efSDag-Erling Smørgrav 		cray_init_job(s->pw); /* set up cray jid and tmpdir */
464f388f5efSDag-Erling Smørgrav #endif
465f388f5efSDag-Erling Smørgrav 
466a04a10f8SKris Kennaway 		/* Do processing for the child (exec command etc). */
467ca3176e7SBrian Feldman 		do_child(s, command);
468a04a10f8SKris Kennaway 		/* NOTREACHED */
469a04a10f8SKris Kennaway 	}
470f388f5efSDag-Erling Smørgrav #ifdef _UNICOS
471f388f5efSDag-Erling Smørgrav 	signal(WJSIGNAL, cray_job_termination_handler);
472f388f5efSDag-Erling Smørgrav #endif /* _UNICOS */
473989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN
474989dd127SDag-Erling Smørgrav 	if (is_winnt)
475989dd127SDag-Erling Smørgrav 		cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
476989dd127SDag-Erling Smørgrav #endif
477a04a10f8SKris Kennaway 	if (pid < 0)
478a04a10f8SKris Kennaway 		packet_disconnect("fork failed: %.100s", strerror(errno));
479a04a10f8SKris Kennaway 	s->pid = pid;
480ca3176e7SBrian Feldman 	/* Set interactive/non-interactive mode. */
481ca3176e7SBrian Feldman 	packet_set_interactive(s->display != NULL);
482a04a10f8SKris Kennaway #ifdef USE_PIPES
483a04a10f8SKris Kennaway 	/* We are the parent.  Close the child sides of the pipes. */
484a04a10f8SKris Kennaway 	close(pin[0]);
485a04a10f8SKris Kennaway 	close(pout[1]);
486a04a10f8SKris Kennaway 	close(perr[1]);
487a04a10f8SKris Kennaway 
488a04a10f8SKris Kennaway 	if (compat20) {
48921e764dfSDag-Erling Smørgrav 		if (s->is_subsystem) {
49021e764dfSDag-Erling Smørgrav 			close(perr[0]);
49121e764dfSDag-Erling Smørgrav 			perr[0] = -1;
49221e764dfSDag-Erling Smørgrav 		}
49321e764dfSDag-Erling Smørgrav 		session_set_fds(s, pin[1], pout[0], perr[0]);
494a04a10f8SKris Kennaway 	} else {
495a04a10f8SKris Kennaway 		/* Enter the interactive session. */
496a04a10f8SKris Kennaway 		server_loop(pid, pin[1], pout[0], perr[0]);
497ca3176e7SBrian Feldman 		/* server_loop has closed pin[1], pout[0], and perr[0]. */
498a04a10f8SKris Kennaway 	}
499a04a10f8SKris Kennaway #else /* USE_PIPES */
500a04a10f8SKris Kennaway 	/* We are the parent.  Close the child sides of the socket pairs. */
501a04a10f8SKris Kennaway 	close(inout[0]);
502a04a10f8SKris Kennaway 	close(err[0]);
503a04a10f8SKris Kennaway 
504a04a10f8SKris Kennaway 	/*
5055962c0e9SDag-Erling Smørgrav 	 * Clear loginmsg, since it's the child's responsibility to display
5065962c0e9SDag-Erling Smørgrav 	 * it to the user, otherwise multiple sessions may accumulate
5075962c0e9SDag-Erling Smørgrav 	 * multiple copies of the login messages.
5085962c0e9SDag-Erling Smørgrav 	 */
5095962c0e9SDag-Erling Smørgrav 	buffer_clear(&loginmsg);
5105962c0e9SDag-Erling Smørgrav 
5115962c0e9SDag-Erling Smørgrav 	/*
512a04a10f8SKris Kennaway 	 * Enter the interactive session.  Note: server_loop must be able to
513a04a10f8SKris Kennaway 	 * handle the case that fdin and fdout are the same.
514a04a10f8SKris Kennaway 	 */
515a04a10f8SKris Kennaway 	if (compat20) {
516ca3176e7SBrian Feldman 		session_set_fds(s, inout[1], inout[1], s->is_subsystem ? -1 : err[1]);
517a04a10f8SKris Kennaway 	} else {
518a04a10f8SKris Kennaway 		server_loop(pid, inout[1], inout[1], err[1]);
519a04a10f8SKris Kennaway 		/* server_loop has closed inout[1] and err[1]. */
520a04a10f8SKris Kennaway 	}
521a04a10f8SKris Kennaway #endif /* USE_PIPES */
522a04a10f8SKris Kennaway }
523a04a10f8SKris Kennaway 
524a04a10f8SKris Kennaway /*
525a04a10f8SKris Kennaway  * This is called to fork and execute a command when we have a tty.  This
526a04a10f8SKris Kennaway  * will call do_child from the child, and server_loop from the parent after
527a04a10f8SKris Kennaway  * setting up file descriptors, controlling tty, updating wtmp, utmp,
528a04a10f8SKris Kennaway  * lastlog, and other such operations.
529a04a10f8SKris Kennaway  */
530a04a10f8SKris Kennaway void
531ca3176e7SBrian Feldman do_exec_pty(Session *s, const char *command)
532a04a10f8SKris Kennaway {
533a04a10f8SKris Kennaway 	int fdout, ptyfd, ttyfd, ptymaster;
534a04a10f8SKris Kennaway 	pid_t pid;
535a04a10f8SKris Kennaway 
536a04a10f8SKris Kennaway 	if (s == NULL)
537a04a10f8SKris Kennaway 		fatal("do_exec_pty: no session");
538a04a10f8SKris Kennaway 	ptyfd = s->ptyfd;
539a04a10f8SKris Kennaway 	ttyfd = s->ttyfd;
540a04a10f8SKris Kennaway 
541989dd127SDag-Erling Smørgrav #if defined(USE_PAM)
542cf2b5f3bSDag-Erling Smørgrav 	if (options.use_pam) {
543cf2b5f3bSDag-Erling Smørgrav 		do_pam_set_tty(s->tty);
5441ec0d754SDag-Erling Smørgrav 		if (!use_privsep)
545989dd127SDag-Erling Smørgrav 			do_pam_setcred(1);
546cf2b5f3bSDag-Erling Smørgrav 	}
547989dd127SDag-Erling Smørgrav #endif
54809958426SBrian Feldman 
549a04a10f8SKris Kennaway 	/* Fork the child. */
550a04a10f8SKris Kennaway 	if ((pid = fork()) == 0) {
5511ec0d754SDag-Erling Smørgrav 		is_child = 1;
552af12a3e7SDag-Erling Smørgrav 
553c2d3a559SKris Kennaway 		/* Child.  Reinitialize the log because the pid has changed. */
554a04a10f8SKris Kennaway 		log_init(__progname, options.log_level, options.log_facility, log_stderr);
555a04a10f8SKris Kennaway 		/* Close the master side of the pseudo tty. */
556a04a10f8SKris Kennaway 		close(ptyfd);
557a04a10f8SKris Kennaway 
558a04a10f8SKris Kennaway 		/* Make the pseudo tty our controlling tty. */
559a04a10f8SKris Kennaway 		pty_make_controlling_tty(&ttyfd, s->tty);
560a04a10f8SKris Kennaway 
561af12a3e7SDag-Erling Smørgrav 		/* Redirect stdin/stdout/stderr from the pseudo tty. */
562af12a3e7SDag-Erling Smørgrav 		if (dup2(ttyfd, 0) < 0)
563af12a3e7SDag-Erling Smørgrav 			error("dup2 stdin: %s", strerror(errno));
564af12a3e7SDag-Erling Smørgrav 		if (dup2(ttyfd, 1) < 0)
565af12a3e7SDag-Erling Smørgrav 			error("dup2 stdout: %s", strerror(errno));
566af12a3e7SDag-Erling Smørgrav 		if (dup2(ttyfd, 2) < 0)
567af12a3e7SDag-Erling Smørgrav 			error("dup2 stderr: %s", strerror(errno));
568a04a10f8SKris Kennaway 
569a04a10f8SKris Kennaway 		/* Close the extra descriptor for the pseudo tty. */
570a04a10f8SKris Kennaway 		close(ttyfd);
571a04a10f8SKris Kennaway 
572c2d3a559SKris Kennaway 		/* record login, etc. similar to login(1) */
573989dd127SDag-Erling Smørgrav #ifndef HAVE_OSF_SIA
574f388f5efSDag-Erling Smørgrav 		if (!(options.use_login && command == NULL)) {
575f388f5efSDag-Erling Smørgrav #ifdef _UNICOS
576f388f5efSDag-Erling Smørgrav 			cray_init_job(s->pw); /* set up cray jid and tmpdir */
577f388f5efSDag-Erling Smørgrav #endif /* _UNICOS */
578ca3176e7SBrian Feldman 			do_login(s, command);
579f388f5efSDag-Erling Smørgrav 		}
580989dd127SDag-Erling Smørgrav # ifdef LOGIN_NEEDS_UTMPX
581989dd127SDag-Erling Smørgrav 		else
582989dd127SDag-Erling Smørgrav 			do_pre_login(s);
583989dd127SDag-Erling Smørgrav # endif
584989dd127SDag-Erling Smørgrav #endif
585e8aafc91SKris Kennaway 
586a04a10f8SKris Kennaway 		/* Do common processing for the child, such as execing the command. */
587ca3176e7SBrian Feldman 		do_child(s, command);
588a04a10f8SKris Kennaway 		/* NOTREACHED */
589a04a10f8SKris Kennaway 	}
590f388f5efSDag-Erling Smørgrav #ifdef _UNICOS
591f388f5efSDag-Erling Smørgrav 	signal(WJSIGNAL, cray_job_termination_handler);
592f388f5efSDag-Erling Smørgrav #endif /* _UNICOS */
593989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN
594989dd127SDag-Erling Smørgrav 	if (is_winnt)
595989dd127SDag-Erling Smørgrav 		cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
596989dd127SDag-Erling Smørgrav #endif
597a04a10f8SKris Kennaway 	if (pid < 0)
598a04a10f8SKris Kennaway 		packet_disconnect("fork failed: %.100s", strerror(errno));
599a04a10f8SKris Kennaway 	s->pid = pid;
600a04a10f8SKris Kennaway 
601a04a10f8SKris Kennaway 	/* Parent.  Close the slave side of the pseudo tty. */
602a04a10f8SKris Kennaway 	close(ttyfd);
603a04a10f8SKris Kennaway 
604a04a10f8SKris Kennaway 	/*
605a04a10f8SKris Kennaway 	 * Create another descriptor of the pty master side for use as the
606a04a10f8SKris Kennaway 	 * standard input.  We could use the original descriptor, but this
607a04a10f8SKris Kennaway 	 * simplifies code in server_loop.  The descriptor is bidirectional.
608a04a10f8SKris Kennaway 	 */
609a04a10f8SKris Kennaway 	fdout = dup(ptyfd);
610a04a10f8SKris Kennaway 	if (fdout < 0)
611a04a10f8SKris Kennaway 		packet_disconnect("dup #1 failed: %.100s", strerror(errno));
612a04a10f8SKris Kennaway 
613a04a10f8SKris Kennaway 	/* we keep a reference to the pty master */
614a04a10f8SKris Kennaway 	ptymaster = dup(ptyfd);
615a04a10f8SKris Kennaway 	if (ptymaster < 0)
616a04a10f8SKris Kennaway 		packet_disconnect("dup #2 failed: %.100s", strerror(errno));
617a04a10f8SKris Kennaway 	s->ptymaster = ptymaster;
618a04a10f8SKris Kennaway 
619a04a10f8SKris Kennaway 	/* Enter interactive session. */
620ca3176e7SBrian Feldman 	packet_set_interactive(1);
621a04a10f8SKris Kennaway 	if (compat20) {
622a04a10f8SKris Kennaway 		session_set_fds(s, ptyfd, fdout, -1);
623a04a10f8SKris Kennaway 	} else {
624a04a10f8SKris Kennaway 		server_loop(pid, ptyfd, fdout, -1);
625a04a10f8SKris Kennaway 		/* server_loop _has_ closed ptyfd and fdout. */
626a04a10f8SKris Kennaway 	}
627a04a10f8SKris Kennaway }
628a04a10f8SKris Kennaway 
629989dd127SDag-Erling Smørgrav #ifdef LOGIN_NEEDS_UTMPX
630989dd127SDag-Erling Smørgrav static void
631989dd127SDag-Erling Smørgrav do_pre_login(Session *s)
632989dd127SDag-Erling Smørgrav {
633989dd127SDag-Erling Smørgrav 	socklen_t fromlen;
634989dd127SDag-Erling Smørgrav 	struct sockaddr_storage from;
635989dd127SDag-Erling Smørgrav 	pid_t pid = getpid();
636989dd127SDag-Erling Smørgrav 
637989dd127SDag-Erling Smørgrav 	/*
638989dd127SDag-Erling Smørgrav 	 * Get IP address of client. If the connection is not a socket, let
639989dd127SDag-Erling Smørgrav 	 * the address be 0.0.0.0.
640989dd127SDag-Erling Smørgrav 	 */
641989dd127SDag-Erling Smørgrav 	memset(&from, 0, sizeof(from));
642989dd127SDag-Erling Smørgrav 	fromlen = sizeof(from);
6437ac32603SHajimu UMEMOTO 	if (packet_connection_is_on_socket()) {
644989dd127SDag-Erling Smørgrav 		if (getpeername(packet_get_connection_in(),
645989dd127SDag-Erling Smørgrav 		    (struct sockaddr *) & from, &fromlen) < 0) {
646989dd127SDag-Erling Smørgrav 			debug("getpeername: %.100s", strerror(errno));
6471ec0d754SDag-Erling Smørgrav 			cleanup_exit(255);
648989dd127SDag-Erling Smørgrav 		}
649989dd127SDag-Erling Smørgrav 	}
650989dd127SDag-Erling Smørgrav 
651989dd127SDag-Erling Smørgrav 	record_utmp_only(pid, s->tty, s->pw->pw_name,
652cf2b5f3bSDag-Erling Smørgrav 	    get_remote_name_or_ip(utmp_len, options.use_dns),
6537ac32603SHajimu UMEMOTO 	    (struct sockaddr *)&from, fromlen);
654989dd127SDag-Erling Smørgrav }
655989dd127SDag-Erling Smørgrav #endif
656989dd127SDag-Erling Smørgrav 
657af12a3e7SDag-Erling Smørgrav /*
658af12a3e7SDag-Erling Smørgrav  * This is called to fork and execute a command.  If another command is
659af12a3e7SDag-Erling Smørgrav  * to be forced, execute that instead.
660af12a3e7SDag-Erling Smørgrav  */
661af12a3e7SDag-Erling Smørgrav void
662af12a3e7SDag-Erling Smørgrav do_exec(Session *s, const char *command)
663af12a3e7SDag-Erling Smørgrav {
664af12a3e7SDag-Erling Smørgrav 	if (forced_command) {
665af12a3e7SDag-Erling Smørgrav 		original_command = command;
666af12a3e7SDag-Erling Smørgrav 		command = forced_command;
667af12a3e7SDag-Erling Smørgrav 		debug("Forced command '%.900s'", command);
668af12a3e7SDag-Erling Smørgrav 	}
669af12a3e7SDag-Erling Smørgrav 
670aa49c926SDag-Erling Smørgrav #ifdef SSH_AUDIT_EVENTS
671aa49c926SDag-Erling Smørgrav 	if (command != NULL)
672aa49c926SDag-Erling Smørgrav 		PRIVSEP(audit_run_command(command));
673aa49c926SDag-Erling Smørgrav 	else if (s->ttyfd == -1) {
674aa49c926SDag-Erling Smørgrav 		char *shell = s->pw->pw_shell;
675aa49c926SDag-Erling Smørgrav 
676aa49c926SDag-Erling Smørgrav 		if (shell[0] == '\0')	/* empty shell means /bin/sh */
677aa49c926SDag-Erling Smørgrav 			shell =_PATH_BSHELL;
678aa49c926SDag-Erling Smørgrav 		PRIVSEP(audit_run_command(shell));
679cf2b5f3bSDag-Erling Smørgrav 	}
680cf2b5f3bSDag-Erling Smørgrav #endif
681cf2b5f3bSDag-Erling Smørgrav 
682af12a3e7SDag-Erling Smørgrav 	if (s->ttyfd != -1)
683af12a3e7SDag-Erling Smørgrav 		do_exec_pty(s, command);
684af12a3e7SDag-Erling Smørgrav 	else
685af12a3e7SDag-Erling Smørgrav 		do_exec_no_pty(s, command);
686af12a3e7SDag-Erling Smørgrav 
687af12a3e7SDag-Erling Smørgrav 	original_command = NULL;
688af12a3e7SDag-Erling Smørgrav 
68921e764dfSDag-Erling Smørgrav 	/*
69021e764dfSDag-Erling Smørgrav 	 * Clear loginmsg: it's the child's responsibility to display
69121e764dfSDag-Erling Smørgrav 	 * it to the user, otherwise multiple sessions may accumulate
69221e764dfSDag-Erling Smørgrav 	 * multiple copies of the login messages.
69321e764dfSDag-Erling Smørgrav 	 */
69421e764dfSDag-Erling Smørgrav 	buffer_clear(&loginmsg);
69521e764dfSDag-Erling Smørgrav }
696af12a3e7SDag-Erling Smørgrav 
697c2d3a559SKris Kennaway /* administrative, login(1)-like work */
698ca3176e7SBrian Feldman void
699c2d3a559SKris Kennaway do_login(Session *s, const char *command)
700c2d3a559SKris Kennaway {
701c2d3a559SKris Kennaway 	socklen_t fromlen;
702c2d3a559SKris Kennaway 	struct sockaddr_storage from;
703c2d3a559SKris Kennaway 	struct passwd * pw = s->pw;
704c2d3a559SKris Kennaway 	pid_t pid = getpid();
705c2d3a559SKris Kennaway 
706c2d3a559SKris Kennaway 	/*
707c2d3a559SKris Kennaway 	 * Get IP address of client. If the connection is not a socket, let
708c2d3a559SKris Kennaway 	 * the address be 0.0.0.0.
709c2d3a559SKris Kennaway 	 */
710c2d3a559SKris Kennaway 	memset(&from, 0, sizeof(from));
711c2d3a559SKris Kennaway 	fromlen = sizeof(from);
7127ac32603SHajimu UMEMOTO 	if (packet_connection_is_on_socket()) {
713c2d3a559SKris Kennaway 		if (getpeername(packet_get_connection_in(),
714c2d3a559SKris Kennaway 		    (struct sockaddr *) & from, &fromlen) < 0) {
715c2d3a559SKris Kennaway 			debug("getpeername: %.100s", strerror(errno));
7161ec0d754SDag-Erling Smørgrav 			cleanup_exit(255);
717c2d3a559SKris Kennaway 		}
718c2d3a559SKris Kennaway 	}
719c2d3a559SKris Kennaway 
72080628bacSDag-Erling Smørgrav 	/* Record that there was a login on that tty from the remote host. */
72180628bacSDag-Erling Smørgrav 	if (!use_privsep)
72280628bacSDag-Erling Smørgrav 		record_login(pid, s->tty, pw->pw_name, pw->pw_uid,
72380628bacSDag-Erling Smørgrav 		    get_remote_name_or_ip(utmp_len,
724cf2b5f3bSDag-Erling Smørgrav 		    options.use_dns),
7257ac32603SHajimu UMEMOTO 		    (struct sockaddr *)&from, fromlen);
72680628bacSDag-Erling Smørgrav 
727098de0c1SAndrey A. Chernov #ifdef USE_PAM
728c2d3a559SKris Kennaway 	/*
729989dd127SDag-Erling Smørgrav 	 * If password change is needed, do it now.
730989dd127SDag-Erling Smørgrav 	 * This needs to occur before the ~/.hushlogin check.
731c2d3a559SKris Kennaway 	 */
7321ec0d754SDag-Erling Smørgrav 	if (options.use_pam && !use_privsep && s->authctxt->force_pwchange) {
7331ec0d754SDag-Erling Smørgrav 		display_loginmsg();
734989dd127SDag-Erling Smørgrav 		do_pam_chauthtok();
7351ec0d754SDag-Erling Smørgrav 		s->authctxt->force_pwchange = 0;
736cf2b5f3bSDag-Erling Smørgrav 		/* XXX - signal [net] parent to enable forwardings */
737989dd127SDag-Erling Smørgrav 	}
738989dd127SDag-Erling Smørgrav #endif
739af12a3e7SDag-Erling Smørgrav 
740989dd127SDag-Erling Smørgrav 	if (check_quietlogin(s, command))
741989dd127SDag-Erling Smørgrav 		return;
742989dd127SDag-Erling Smørgrav 
7431ec0d754SDag-Erling Smørgrav 	display_loginmsg();
744f388f5efSDag-Erling Smørgrav 
745ca3176e7SBrian Feldman 	do_motd();
746ca3176e7SBrian Feldman }
747ca3176e7SBrian Feldman 
748ca3176e7SBrian Feldman /*
749ca3176e7SBrian Feldman  * Display the message of the day.
750ca3176e7SBrian Feldman  */
751ca3176e7SBrian Feldman void
752ca3176e7SBrian Feldman do_motd(void)
753ca3176e7SBrian Feldman {
754ca3176e7SBrian Feldman 	FILE *f;
755ca3176e7SBrian Feldman 	char buf[256];
75659ac432aSAndrey A. Chernov #ifdef HAVE_LOGIN_CAP
75759ac432aSAndrey A. Chernov 	const char *fname;
75859ac432aSAndrey A. Chernov #endif
75959ac432aSAndrey A. Chernov 
76059ac432aSAndrey A. Chernov #ifdef HAVE_LOGIN_CAP
76159ac432aSAndrey A. Chernov 	fname = login_getcapstr(lc, "copyright", NULL, NULL);
76259ac432aSAndrey A. Chernov 	if (fname != NULL && (f = fopen(fname, "r")) != NULL) {
76359ac432aSAndrey A. Chernov 		while (fgets(buf, sizeof(buf), f) != NULL)
76459ac432aSAndrey A. Chernov 			fputs(buf, stdout);
76559ac432aSAndrey A. Chernov 			fclose(f);
76659ac432aSAndrey A. Chernov 	} else
76759ac432aSAndrey A. Chernov #endif /* HAVE_LOGIN_CAP */
76859ac432aSAndrey A. Chernov 		(void)printf("%s\n\t%s %s\n",
76959ac432aSAndrey A. Chernov 	"Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
77059ac432aSAndrey A. Chernov 	"The Regents of the University of California. ",
77159ac432aSAndrey A. Chernov 	"All rights reserved.");
77259ac432aSAndrey A. Chernov 
77359ac432aSAndrey A. Chernov 	(void)printf("\n");
774ca3176e7SBrian Feldman 
775ca3176e7SBrian Feldman 	if (options.print_motd) {
776c2d3a559SKris Kennaway #ifdef HAVE_LOGIN_CAP
777c2d3a559SKris Kennaway 		f = fopen(login_getcapstr(lc, "welcome", "/etc/motd",
778c2d3a559SKris Kennaway 		    "/etc/motd"), "r");
779af12a3e7SDag-Erling Smørgrav #else
780c2d3a559SKris Kennaway 		f = fopen("/etc/motd", "r");
781af12a3e7SDag-Erling Smørgrav #endif
782c2d3a559SKris Kennaway 		if (f) {
783c2d3a559SKris Kennaway 			while (fgets(buf, sizeof(buf), f))
784c2d3a559SKris Kennaway 				fputs(buf, stdout);
785c2d3a559SKris Kennaway 			fclose(f);
786c2d3a559SKris Kennaway 		}
787c2d3a559SKris Kennaway 	}
788ca3176e7SBrian Feldman }
789c2d3a559SKris Kennaway 
790af12a3e7SDag-Erling Smørgrav 
791ca3176e7SBrian Feldman /*
792ca3176e7SBrian Feldman  * Check for quiet login, either .hushlogin or command given.
793ca3176e7SBrian Feldman  */
794ca3176e7SBrian Feldman int
795ca3176e7SBrian Feldman check_quietlogin(Session *s, const char *command)
796ca3176e7SBrian Feldman {
797ca3176e7SBrian Feldman 	char buf[256];
798ca3176e7SBrian Feldman 	struct passwd *pw = s->pw;
799ca3176e7SBrian Feldman 	struct stat st;
800ca3176e7SBrian Feldman 
801ca3176e7SBrian Feldman 	/* Return 1 if .hushlogin exists or a command given. */
802ca3176e7SBrian Feldman 	if (command != NULL)
803ca3176e7SBrian Feldman 		return 1;
804ca3176e7SBrian Feldman 	snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir);
805c2d3a559SKris Kennaway #ifdef HAVE_LOGIN_CAP
806ca3176e7SBrian Feldman 	if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0)
807ca3176e7SBrian Feldman 		return 1;
808ca3176e7SBrian Feldman #else
809ca3176e7SBrian Feldman 	if (stat(buf, &st) >= 0)
810ca3176e7SBrian Feldman 		return 1;
811ca3176e7SBrian Feldman #endif
812ca3176e7SBrian Feldman 	return 0;
813c2d3a559SKris Kennaway }
814c2d3a559SKris Kennaway 
815a04a10f8SKris Kennaway /*
816a04a10f8SKris Kennaway  * Sets the value of the given variable in the environment.  If the variable
817a04a10f8SKris Kennaway  * already exists, its value is overriden.
818a04a10f8SKris Kennaway  */
819cf2b5f3bSDag-Erling Smørgrav void
820ca3176e7SBrian Feldman child_set_env(char ***envp, u_int *envsizep, const char *name,
821a04a10f8SKris Kennaway 	const char *value)
822a04a10f8SKris Kennaway {
823a04a10f8SKris Kennaway 	char **env;
824b69cd7f2SJacques Vidrine 	u_int envsize;
825b69cd7f2SJacques Vidrine 	u_int i, namelen;
826a04a10f8SKris Kennaway 
827a04a10f8SKris Kennaway 	/*
828cf2b5f3bSDag-Erling Smørgrav 	 * If we're passed an uninitialized list, allocate a single null
829cf2b5f3bSDag-Erling Smørgrav 	 * entry before continuing.
830cf2b5f3bSDag-Erling Smørgrav 	 */
831cf2b5f3bSDag-Erling Smørgrav 	if (*envp == NULL && *envsizep == 0) {
832cf2b5f3bSDag-Erling Smørgrav 		*envp = xmalloc(sizeof(char *));
833cf2b5f3bSDag-Erling Smørgrav 		*envp[0] = NULL;
834cf2b5f3bSDag-Erling Smørgrav 		*envsizep = 1;
835cf2b5f3bSDag-Erling Smørgrav 	}
836cf2b5f3bSDag-Erling Smørgrav 
837cf2b5f3bSDag-Erling Smørgrav 	/*
838a04a10f8SKris Kennaway 	 * Find the slot where the value should be stored.  If the variable
839a04a10f8SKris Kennaway 	 * already exists, we reuse the slot; otherwise we append a new slot
840a04a10f8SKris Kennaway 	 * at the end of the array, expanding if necessary.
841a04a10f8SKris Kennaway 	 */
842a04a10f8SKris Kennaway 	env = *envp;
843a04a10f8SKris Kennaway 	namelen = strlen(name);
844a04a10f8SKris Kennaway 	for (i = 0; env[i]; i++)
845a04a10f8SKris Kennaway 		if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
846a04a10f8SKris Kennaway 			break;
847a04a10f8SKris Kennaway 	if (env[i]) {
848a04a10f8SKris Kennaway 		/* Reuse the slot. */
849a04a10f8SKris Kennaway 		xfree(env[i]);
850a04a10f8SKris Kennaway 	} else {
851a04a10f8SKris Kennaway 		/* New variable.  Expand if necessary. */
852b69cd7f2SJacques Vidrine 		envsize = *envsizep;
853b69cd7f2SJacques Vidrine 		if (i >= envsize - 1) {
854b69cd7f2SJacques Vidrine 			if (envsize >= 1000)
855b69cd7f2SJacques Vidrine 				fatal("child_set_env: too many env vars");
856b69cd7f2SJacques Vidrine 			envsize += 50;
857b69cd7f2SJacques Vidrine 			env = (*envp) = xrealloc(env, envsize * sizeof(char *));
858b69cd7f2SJacques Vidrine 			*envsizep = envsize;
859a04a10f8SKris Kennaway 		}
860a04a10f8SKris Kennaway 		/* Need to set the NULL pointer at end of array beyond the new slot. */
861a04a10f8SKris Kennaway 		env[i + 1] = NULL;
862a04a10f8SKris Kennaway 	}
863a04a10f8SKris Kennaway 
864a04a10f8SKris Kennaway 	/* Allocate space and format the variable in the appropriate slot. */
865a04a10f8SKris Kennaway 	env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
866a04a10f8SKris Kennaway 	snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
867a04a10f8SKris Kennaway }
868a04a10f8SKris Kennaway 
869a04a10f8SKris Kennaway /*
870a04a10f8SKris Kennaway  * Reads environment variables from the given file and adds/overrides them
871a04a10f8SKris Kennaway  * into the environment.  If the file does not exist, this does nothing.
872a04a10f8SKris Kennaway  * Otherwise, it must consist of empty lines, comments (line starts with '#')
873a04a10f8SKris Kennaway  * and assignments of the form name=value.  No other forms are allowed.
874a04a10f8SKris Kennaway  */
875af12a3e7SDag-Erling Smørgrav static void
876ca3176e7SBrian Feldman read_environment_file(char ***env, u_int *envsize,
877a04a10f8SKris Kennaway 	const char *filename)
878a04a10f8SKris Kennaway {
879a04a10f8SKris Kennaway 	FILE *f;
880a04a10f8SKris Kennaway 	char buf[4096];
881a04a10f8SKris Kennaway 	char *cp, *value;
882a82e551fSDag-Erling Smørgrav 	u_int lineno = 0;
883a04a10f8SKris Kennaway 
884a04a10f8SKris Kennaway 	f = fopen(filename, "r");
885a04a10f8SKris Kennaway 	if (!f)
886a04a10f8SKris Kennaway 		return;
887a04a10f8SKris Kennaway 
888a04a10f8SKris Kennaway 	while (fgets(buf, sizeof(buf), f)) {
889a82e551fSDag-Erling Smørgrav 		if (++lineno > 1000)
890a82e551fSDag-Erling Smørgrav 			fatal("Too many lines in environment file %s", filename);
891a04a10f8SKris Kennaway 		for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
892a04a10f8SKris Kennaway 			;
893a04a10f8SKris Kennaway 		if (!*cp || *cp == '#' || *cp == '\n')
894a04a10f8SKris Kennaway 			continue;
895a04a10f8SKris Kennaway 		if (strchr(cp, '\n'))
896a04a10f8SKris Kennaway 			*strchr(cp, '\n') = '\0';
897a04a10f8SKris Kennaway 		value = strchr(cp, '=');
898a04a10f8SKris Kennaway 		if (value == NULL) {
899a82e551fSDag-Erling Smørgrav 			fprintf(stderr, "Bad line %u in %.100s\n", lineno,
900a82e551fSDag-Erling Smørgrav 			    filename);
901a04a10f8SKris Kennaway 			continue;
902a04a10f8SKris Kennaway 		}
903db1cb46cSKris Kennaway 		/*
904db1cb46cSKris Kennaway 		 * Replace the equals sign by nul, and advance value to
905db1cb46cSKris Kennaway 		 * the value string.
906db1cb46cSKris Kennaway 		 */
907a04a10f8SKris Kennaway 		*value = '\0';
908a04a10f8SKris Kennaway 		value++;
909a04a10f8SKris Kennaway 		child_set_env(env, envsize, cp, value);
910a04a10f8SKris Kennaway 	}
911a04a10f8SKris Kennaway 	fclose(f);
912a04a10f8SKris Kennaway }
913a04a10f8SKris Kennaway 
914cf2b5f3bSDag-Erling Smørgrav #ifdef HAVE_ETC_DEFAULT_LOGIN
915cf2b5f3bSDag-Erling Smørgrav /*
916cf2b5f3bSDag-Erling Smørgrav  * Return named variable from specified environment, or NULL if not present.
917cf2b5f3bSDag-Erling Smørgrav  */
918cf2b5f3bSDag-Erling Smørgrav static char *
919cf2b5f3bSDag-Erling Smørgrav child_get_env(char **env, const char *name)
920cf2b5f3bSDag-Erling Smørgrav {
921cf2b5f3bSDag-Erling Smørgrav 	int i;
922cf2b5f3bSDag-Erling Smørgrav 	size_t len;
923cf2b5f3bSDag-Erling Smørgrav 
924cf2b5f3bSDag-Erling Smørgrav 	len = strlen(name);
925cf2b5f3bSDag-Erling Smørgrav 	for (i=0; env[i] != NULL; i++)
926cf2b5f3bSDag-Erling Smørgrav 		if (strncmp(name, env[i], len) == 0 && env[i][len] == '=')
927cf2b5f3bSDag-Erling Smørgrav 			return(env[i] + len + 1);
928cf2b5f3bSDag-Erling Smørgrav 	return NULL;
929cf2b5f3bSDag-Erling Smørgrav }
930cf2b5f3bSDag-Erling Smørgrav 
931cf2b5f3bSDag-Erling Smørgrav /*
932cf2b5f3bSDag-Erling Smørgrav  * Read /etc/default/login.
933cf2b5f3bSDag-Erling Smørgrav  * We pick up the PATH (or SUPATH for root) and UMASK.
934cf2b5f3bSDag-Erling Smørgrav  */
935cf2b5f3bSDag-Erling Smørgrav static void
936cf2b5f3bSDag-Erling Smørgrav read_etc_default_login(char ***env, u_int *envsize, uid_t uid)
937cf2b5f3bSDag-Erling Smørgrav {
938cf2b5f3bSDag-Erling Smørgrav 	char **tmpenv = NULL, *var;
939cf2b5f3bSDag-Erling Smørgrav 	u_int i, tmpenvsize = 0;
9401ec0d754SDag-Erling Smørgrav 	u_long mask;
941cf2b5f3bSDag-Erling Smørgrav 
942cf2b5f3bSDag-Erling Smørgrav 	/*
943cf2b5f3bSDag-Erling Smørgrav 	 * We don't want to copy the whole file to the child's environment,
944cf2b5f3bSDag-Erling Smørgrav 	 * so we use a temporary environment and copy the variables we're
945cf2b5f3bSDag-Erling Smørgrav 	 * interested in.
946cf2b5f3bSDag-Erling Smørgrav 	 */
947cf2b5f3bSDag-Erling Smørgrav 	read_environment_file(&tmpenv, &tmpenvsize, "/etc/default/login");
948cf2b5f3bSDag-Erling Smørgrav 
949cf2b5f3bSDag-Erling Smørgrav 	if (tmpenv == NULL)
950cf2b5f3bSDag-Erling Smørgrav 		return;
951cf2b5f3bSDag-Erling Smørgrav 
952cf2b5f3bSDag-Erling Smørgrav 	if (uid == 0)
953cf2b5f3bSDag-Erling Smørgrav 		var = child_get_env(tmpenv, "SUPATH");
954cf2b5f3bSDag-Erling Smørgrav 	else
955cf2b5f3bSDag-Erling Smørgrav 		var = child_get_env(tmpenv, "PATH");
956cf2b5f3bSDag-Erling Smørgrav 	if (var != NULL)
957cf2b5f3bSDag-Erling Smørgrav 		child_set_env(env, envsize, "PATH", var);
958cf2b5f3bSDag-Erling Smørgrav 
959cf2b5f3bSDag-Erling Smørgrav 	if ((var = child_get_env(tmpenv, "UMASK")) != NULL)
960cf2b5f3bSDag-Erling Smørgrav 		if (sscanf(var, "%5lo", &mask) == 1)
9611ec0d754SDag-Erling Smørgrav 			umask((mode_t)mask);
962cf2b5f3bSDag-Erling Smørgrav 
963cf2b5f3bSDag-Erling Smørgrav 	for (i = 0; tmpenv[i] != NULL; i++)
964cf2b5f3bSDag-Erling Smørgrav 		xfree(tmpenv[i]);
965cf2b5f3bSDag-Erling Smørgrav 	xfree(tmpenv);
966cf2b5f3bSDag-Erling Smørgrav }
967cf2b5f3bSDag-Erling Smørgrav #endif /* HAVE_ETC_DEFAULT_LOGIN */
968cf2b5f3bSDag-Erling Smørgrav 
969d4ecd108SDag-Erling Smørgrav void
970d4ecd108SDag-Erling Smørgrav copy_environment(char **source, char ***env, u_int *envsize)
97109958426SBrian Feldman {
972989dd127SDag-Erling Smørgrav 	char *var_name, *var_val;
97309958426SBrian Feldman 	int i;
97409958426SBrian Feldman 
975989dd127SDag-Erling Smørgrav 	if (source == NULL)
97609958426SBrian Feldman 		return;
97709958426SBrian Feldman 
978989dd127SDag-Erling Smørgrav 	for(i = 0; source[i] != NULL; i++) {
979989dd127SDag-Erling Smørgrav 		var_name = xstrdup(source[i]);
980989dd127SDag-Erling Smørgrav 		if ((var_val = strstr(var_name, "=")) == NULL) {
981989dd127SDag-Erling Smørgrav 			xfree(var_name);
98209958426SBrian Feldman 			continue;
983989dd127SDag-Erling Smørgrav 		}
984989dd127SDag-Erling Smørgrav 		*var_val++ = '\0';
98509958426SBrian Feldman 
986989dd127SDag-Erling Smørgrav 		debug3("Copy environment: %s=%s", var_name, var_val);
98709958426SBrian Feldman 		child_set_env(env, envsize, var_name, var_val);
988989dd127SDag-Erling Smørgrav 
989989dd127SDag-Erling Smørgrav 		xfree(var_name);
99009958426SBrian Feldman 	}
99109958426SBrian Feldman }
99209958426SBrian Feldman 
993af12a3e7SDag-Erling Smørgrav static char **
994989dd127SDag-Erling Smørgrav do_setup_env(Session *s, const char *shell)
995a04a10f8SKris Kennaway {
996a04a10f8SKris Kennaway 	char buf[256];
997af12a3e7SDag-Erling Smørgrav 	u_int i, envsize;
998cf2b5f3bSDag-Erling Smørgrav 	char **env, *laddr, *path = NULL;
999c62005fcSDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1000c62005fcSDag-Erling Smørgrav 	extern char **environ;
1001c62005fcSDag-Erling Smørgrav 	char **senv, **var;
1002c62005fcSDag-Erling Smørgrav #endif
1003af12a3e7SDag-Erling Smørgrav 	struct passwd *pw = s->pw;
1004a04a10f8SKris Kennaway 
1005a04a10f8SKris Kennaway 	/* Initialize the environment. */
1006a04a10f8SKris Kennaway 	envsize = 100;
1007a04a10f8SKris Kennaway 	env = xmalloc(envsize * sizeof(char *));
1008a04a10f8SKris Kennaway 	env[0] = NULL;
1009989dd127SDag-Erling Smørgrav 
1010989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN
1011989dd127SDag-Erling Smørgrav 	/*
1012989dd127SDag-Erling Smørgrav 	 * The Windows environment contains some setting which are
1013989dd127SDag-Erling Smørgrav 	 * important for a running system. They must not be dropped.
1014989dd127SDag-Erling Smørgrav 	 */
1015aa49c926SDag-Erling Smørgrav 	{
1016aa49c926SDag-Erling Smørgrav 		char **p;
1017aa49c926SDag-Erling Smørgrav 
1018aa49c926SDag-Erling Smørgrav 		p = fetch_windows_environment();
1019aa49c926SDag-Erling Smørgrav 		copy_environment(p, &env, &envsize);
1020aa49c926SDag-Erling Smørgrav 		free_windows_environment(p);
1021aa49c926SDag-Erling Smørgrav 	}
1022989dd127SDag-Erling Smørgrav #endif
1023a04a10f8SKris Kennaway 
1024c62005fcSDag-Erling Smørgrav 	if (getenv("TZ"))
1025c62005fcSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "TZ", getenv("TZ"));
1026cf2b5f3bSDag-Erling Smørgrav 
1027cf2b5f3bSDag-Erling Smørgrav #ifdef GSSAPI
1028cf2b5f3bSDag-Erling Smørgrav 	/* Allow any GSSAPI methods that we've used to alter
1029cf2b5f3bSDag-Erling Smørgrav 	 * the childs environment as they see fit
1030cf2b5f3bSDag-Erling Smørgrav 	 */
1031cf2b5f3bSDag-Erling Smørgrav 	ssh_gssapi_do_child(&env, &envsize);
1032cf2b5f3bSDag-Erling Smørgrav #endif
1033cf2b5f3bSDag-Erling Smørgrav 
1034a04a10f8SKris Kennaway 	if (!options.use_login) {
1035a04a10f8SKris Kennaway 		/* Set basic environment. */
103621e764dfSDag-Erling Smørgrav 		for (i = 0; i < s->num_env; i++)
103721e764dfSDag-Erling Smørgrav 			child_set_env(&env, &envsize, s->env[i].name,
103821e764dfSDag-Erling Smørgrav 			    s->env[i].val);
103921e764dfSDag-Erling Smørgrav 
1040a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, "USER", pw->pw_name);
1041a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
1042e73e9afaSDag-Erling Smørgrav #ifdef _AIX
1043e73e9afaSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "LOGIN", pw->pw_name);
1044e73e9afaSDag-Erling Smørgrav #endif
1045a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, "HOME", pw->pw_dir);
1046c62005fcSDag-Erling Smørgrav 		snprintf(buf, sizeof buf, "%.200s/%.50s",
1047c62005fcSDag-Erling Smørgrav 			 _PATH_MAILDIR, pw->pw_name);
1048c62005fcSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "MAIL", buf);
1049989dd127SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1050c62005fcSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
1051c62005fcSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "TERM", "su");
1052c62005fcSDag-Erling Smørgrav 		senv = environ;
1053c62005fcSDag-Erling Smørgrav 		environ = xmalloc(sizeof(char *));
1054c62005fcSDag-Erling Smørgrav 		*environ = NULL;
1055c62005fcSDag-Erling Smørgrav 		(void) setusercontext(lc, pw, pw->pw_uid,
1056c62005fcSDag-Erling Smørgrav 		    LOGIN_SETENV|LOGIN_SETPATH);
1057c62005fcSDag-Erling Smørgrav 		copy_environment(environ, &env, &envsize);
1058c62005fcSDag-Erling Smørgrav 		for (var = environ; *var != NULL; ++var)
1059c62005fcSDag-Erling Smørgrav 			xfree(*var);
1060c62005fcSDag-Erling Smørgrav 		xfree(environ);
1061c62005fcSDag-Erling Smørgrav 		environ = senv;
1062989dd127SDag-Erling Smørgrav #else /* HAVE_LOGIN_CAP */
1063989dd127SDag-Erling Smørgrav # ifndef HAVE_CYGWIN
1064989dd127SDag-Erling Smørgrav 		/*
1065989dd127SDag-Erling Smørgrav 		 * There's no standard path on Windows. The path contains
1066989dd127SDag-Erling Smørgrav 		 * important components pointing to the system directories,
1067989dd127SDag-Erling Smørgrav 		 * needed for loading shared libraries. So the path better
1068989dd127SDag-Erling Smørgrav 		 * remains intact here.
1069989dd127SDag-Erling Smørgrav 		 */
1070cf2b5f3bSDag-Erling Smørgrav #  ifdef HAVE_ETC_DEFAULT_LOGIN
1071cf2b5f3bSDag-Erling Smørgrav 		read_etc_default_login(&env, &envsize, pw->pw_uid);
1072cf2b5f3bSDag-Erling Smørgrav 		path = child_get_env(env, "PATH");
1073cf2b5f3bSDag-Erling Smørgrav #  endif /* HAVE_ETC_DEFAULT_LOGIN */
1074cf2b5f3bSDag-Erling Smørgrav 		if (path == NULL || *path == '\0') {
1075989dd127SDag-Erling Smørgrav 			child_set_env(&env, &envsize, "PATH",
1076cf2b5f3bSDag-Erling Smørgrav 			    s->pw->pw_uid == 0 ?
1077cf2b5f3bSDag-Erling Smørgrav 				SUPERUSER_PATH : _PATH_STDPATH);
1078cf2b5f3bSDag-Erling Smørgrav 		}
1079989dd127SDag-Erling Smørgrav # endif /* HAVE_CYGWIN */
1080989dd127SDag-Erling Smørgrav #endif /* HAVE_LOGIN_CAP */
1081a04a10f8SKris Kennaway 
1082a04a10f8SKris Kennaway 		/* Normal systems set SHELL by default. */
1083a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, "SHELL", shell);
1084a04a10f8SKris Kennaway 	}
1085a04a10f8SKris Kennaway 
1086a04a10f8SKris Kennaway 	/* Set custom environment options from RSA authentication. */
10871c5093bbSJacques Vidrine 	if (!options.use_login) {
1088a04a10f8SKris Kennaway 		while (custom_environment) {
1089a04a10f8SKris Kennaway 			struct envstring *ce = custom_environment;
1090f388f5efSDag-Erling Smørgrav 			char *str = ce->s;
1091af12a3e7SDag-Erling Smørgrav 
1092f388f5efSDag-Erling Smørgrav 			for (i = 0; str[i] != '=' && str[i]; i++)
1093af12a3e7SDag-Erling Smørgrav 				;
1094f388f5efSDag-Erling Smørgrav 			if (str[i] == '=') {
1095f388f5efSDag-Erling Smørgrav 				str[i] = 0;
1096f388f5efSDag-Erling Smørgrav 				child_set_env(&env, &envsize, str, str + i + 1);
1097a04a10f8SKris Kennaway 			}
1098a04a10f8SKris Kennaway 			custom_environment = ce->next;
1099a04a10f8SKris Kennaway 			xfree(ce->s);
1100a04a10f8SKris Kennaway 			xfree(ce);
1101a04a10f8SKris Kennaway 		}
11021c5093bbSJacques Vidrine 	}
1103a04a10f8SKris Kennaway 
1104f388f5efSDag-Erling Smørgrav 	/* SSH_CLIENT deprecated */
1105a04a10f8SKris Kennaway 	snprintf(buf, sizeof buf, "%.50s %d %d",
1106a04a10f8SKris Kennaway 	    get_remote_ipaddr(), get_remote_port(), get_local_port());
1107a04a10f8SKris Kennaway 	child_set_env(&env, &envsize, "SSH_CLIENT", buf);
1108a04a10f8SKris Kennaway 
1109e73e9afaSDag-Erling Smørgrav 	laddr = get_local_ipaddr(packet_get_connection_in());
1110f388f5efSDag-Erling Smørgrav 	snprintf(buf, sizeof buf, "%.50s %d %.50s %d",
1111e73e9afaSDag-Erling Smørgrav 	    get_remote_ipaddr(), get_remote_port(), laddr, get_local_port());
1112e73e9afaSDag-Erling Smørgrav 	xfree(laddr);
1113f388f5efSDag-Erling Smørgrav 	child_set_env(&env, &envsize, "SSH_CONNECTION", buf);
1114f388f5efSDag-Erling Smørgrav 
1115ca3176e7SBrian Feldman 	if (s->ttyfd != -1)
1116ca3176e7SBrian Feldman 		child_set_env(&env, &envsize, "SSH_TTY", s->tty);
1117ca3176e7SBrian Feldman 	if (s->term)
1118ca3176e7SBrian Feldman 		child_set_env(&env, &envsize, "TERM", s->term);
1119ca3176e7SBrian Feldman 	if (s->display)
1120ca3176e7SBrian Feldman 		child_set_env(&env, &envsize, "DISPLAY", s->display);
1121c2d3a559SKris Kennaway 	if (original_command)
1122c2d3a559SKris Kennaway 		child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND",
1123c2d3a559SKris Kennaway 		    original_command);
1124989dd127SDag-Erling Smørgrav 
1125f388f5efSDag-Erling Smørgrav #ifdef _UNICOS
1126f388f5efSDag-Erling Smørgrav 	if (cray_tmpdir[0] != '\0')
1127f388f5efSDag-Erling Smørgrav 		child_set_env(&env, &envsize, "TMPDIR", cray_tmpdir);
1128f388f5efSDag-Erling Smørgrav #endif /* _UNICOS */
1129f388f5efSDag-Erling Smørgrav 
1130aa49c926SDag-Erling Smørgrav 	/*
1131aa49c926SDag-Erling Smørgrav 	 * Since we clear KRB5CCNAME at startup, if it's set now then it
1132aa49c926SDag-Erling Smørgrav 	 * must have been set by a native authentication method (eg AIX or
1133aa49c926SDag-Erling Smørgrav 	 * SIA), so copy it to the child.
1134aa49c926SDag-Erling Smørgrav 	 */
1135aa49c926SDag-Erling Smørgrav 	{
1136aa49c926SDag-Erling Smørgrav 		char *cp;
1137aa49c926SDag-Erling Smørgrav 
1138aa49c926SDag-Erling Smørgrav 		if ((cp = getenv("KRB5CCNAME")) != NULL)
1139aa49c926SDag-Erling Smørgrav 			child_set_env(&env, &envsize, "KRB5CCNAME", cp);
1140aa49c926SDag-Erling Smørgrav 	}
1141aa49c926SDag-Erling Smørgrav 
1142989dd127SDag-Erling Smørgrav #ifdef _AIX
1143989dd127SDag-Erling Smørgrav 	{
1144989dd127SDag-Erling Smørgrav 		char *cp;
1145989dd127SDag-Erling Smørgrav 
1146989dd127SDag-Erling Smørgrav 		if ((cp = getenv("AUTHSTATE")) != NULL)
1147989dd127SDag-Erling Smørgrav 			child_set_env(&env, &envsize, "AUTHSTATE", cp);
1148989dd127SDag-Erling Smørgrav 		read_environment_file(&env, &envsize, "/etc/environment");
1149989dd127SDag-Erling Smørgrav 	}
1150989dd127SDag-Erling Smørgrav #endif
1151e8aafc91SKris Kennaway #ifdef KRB5
11525962c0e9SDag-Erling Smørgrav 	if (s->authctxt->krb5_ccname)
1153af12a3e7SDag-Erling Smørgrav 		child_set_env(&env, &envsize, "KRB5CCNAME",
11545962c0e9SDag-Erling Smørgrav 		    s->authctxt->krb5_ccname);
1155af12a3e7SDag-Erling Smørgrav #endif
115609958426SBrian Feldman #ifdef USE_PAM
1157f388f5efSDag-Erling Smørgrav 	/*
1158f388f5efSDag-Erling Smørgrav 	 * Pull in any environment variables that may have
1159f388f5efSDag-Erling Smørgrav 	 * been set by PAM.
1160f388f5efSDag-Erling Smørgrav 	 */
1161cf2b5f3bSDag-Erling Smørgrav 	if (options.use_pam) {
11621ec0d754SDag-Erling Smørgrav 		char **p;
1163f388f5efSDag-Erling Smørgrav 
11641ec0d754SDag-Erling Smørgrav 		p = fetch_pam_child_environment();
11651ec0d754SDag-Erling Smørgrav 		copy_environment(p, &env, &envsize);
11661ec0d754SDag-Erling Smørgrav 		free_pam_environment(p);
11671ec0d754SDag-Erling Smørgrav 
11681ec0d754SDag-Erling Smørgrav 		p = fetch_pam_environment();
1169f388f5efSDag-Erling Smørgrav 		copy_environment(p, &env, &envsize);
1170f388f5efSDag-Erling Smørgrav 		free_pam_environment(p);
1171f388f5efSDag-Erling Smørgrav 	}
117209958426SBrian Feldman #endif /* USE_PAM */
117309958426SBrian Feldman 
117480628bacSDag-Erling Smørgrav 	if (auth_sock_name != NULL)
1175a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
117680628bacSDag-Erling Smørgrav 		    auth_sock_name);
1177a04a10f8SKris Kennaway 
1178a04a10f8SKris Kennaway 	/* read $HOME/.ssh/environment. */
1179f388f5efSDag-Erling Smørgrav 	if (options.permit_user_env && !options.use_login) {
1180db1cb46cSKris Kennaway 		snprintf(buf, sizeof buf, "%.200s/.ssh/environment",
1181f388f5efSDag-Erling Smørgrav 		    strcmp(pw->pw_dir, "/") ? pw->pw_dir : "");
1182a04a10f8SKris Kennaway 		read_environment_file(&env, &envsize, buf);
1183a04a10f8SKris Kennaway 	}
1184a04a10f8SKris Kennaway 	if (debug_flag) {
1185a04a10f8SKris Kennaway 		/* dump the environment */
1186a04a10f8SKris Kennaway 		fprintf(stderr, "Environment:\n");
1187a04a10f8SKris Kennaway 		for (i = 0; env[i]; i++)
1188a04a10f8SKris Kennaway 			fprintf(stderr, "  %.200s\n", env[i]);
1189a04a10f8SKris Kennaway 	}
1190af12a3e7SDag-Erling Smørgrav 	return env;
1191e8aafc91SKris Kennaway }
1192ca3176e7SBrian Feldman 
1193ca3176e7SBrian Feldman /*
1194af12a3e7SDag-Erling Smørgrav  * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found
1195af12a3e7SDag-Erling Smørgrav  * first in this order).
1196ca3176e7SBrian Feldman  */
1197af12a3e7SDag-Erling Smørgrav static void
1198af12a3e7SDag-Erling Smørgrav do_rc_files(Session *s, const char *shell)
1199af12a3e7SDag-Erling Smørgrav {
1200af12a3e7SDag-Erling Smørgrav 	FILE *f = NULL;
1201af12a3e7SDag-Erling Smørgrav 	char cmd[1024];
1202af12a3e7SDag-Erling Smørgrav 	int do_xauth;
1203af12a3e7SDag-Erling Smørgrav 	struct stat st;
1204a04a10f8SKris Kennaway 
1205af12a3e7SDag-Erling Smørgrav 	do_xauth =
1206af12a3e7SDag-Erling Smørgrav 	    s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL;
1207a04a10f8SKris Kennaway 
1208ca3176e7SBrian Feldman 	/* ignore _PATH_SSH_USER_RC for subsystems */
1209ca3176e7SBrian Feldman 	if (!s->is_subsystem && (stat(_PATH_SSH_USER_RC, &st) >= 0)) {
1210e9fd63dfSBrian Feldman 		snprintf(cmd, sizeof cmd, "%s -c '%s %s'",
1211e9fd63dfSBrian Feldman 		    shell, _PATH_BSHELL, _PATH_SSH_USER_RC);
1212a04a10f8SKris Kennaway 		if (debug_flag)
1213e9fd63dfSBrian Feldman 			fprintf(stderr, "Running %s\n", cmd);
1214e9fd63dfSBrian Feldman 		f = popen(cmd, "w");
1215a04a10f8SKris Kennaway 		if (f) {
1216ca3176e7SBrian Feldman 			if (do_xauth)
1217ca3176e7SBrian Feldman 				fprintf(f, "%s %s\n", s->auth_proto,
1218ca3176e7SBrian Feldman 				    s->auth_data);
1219a04a10f8SKris Kennaway 			pclose(f);
1220a04a10f8SKris Kennaway 		} else
1221ca3176e7SBrian Feldman 			fprintf(stderr, "Could not run %s\n",
1222ca3176e7SBrian Feldman 			    _PATH_SSH_USER_RC);
1223ca3176e7SBrian Feldman 	} else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) {
1224a04a10f8SKris Kennaway 		if (debug_flag)
1225ca3176e7SBrian Feldman 			fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,
1226ca3176e7SBrian Feldman 			    _PATH_SSH_SYSTEM_RC);
1227ca3176e7SBrian Feldman 		f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w");
1228a04a10f8SKris Kennaway 		if (f) {
1229ca3176e7SBrian Feldman 			if (do_xauth)
1230ca3176e7SBrian Feldman 				fprintf(f, "%s %s\n", s->auth_proto,
1231ca3176e7SBrian Feldman 				    s->auth_data);
1232a04a10f8SKris Kennaway 			pclose(f);
1233a04a10f8SKris Kennaway 		} else
1234ca3176e7SBrian Feldman 			fprintf(stderr, "Could not run %s\n",
1235ca3176e7SBrian Feldman 			    _PATH_SSH_SYSTEM_RC);
1236ca3176e7SBrian Feldman 	} else if (do_xauth && options.xauth_location != NULL) {
1237a04a10f8SKris Kennaway 		/* Add authority data to .Xauthority if appropriate. */
1238db1cb46cSKris Kennaway 		if (debug_flag) {
1239db1cb46cSKris Kennaway 			fprintf(stderr,
1240e73e9afaSDag-Erling Smørgrav 			    "Running %.500s remove %.100s\n",
1241e73e9afaSDag-Erling Smørgrav 			    options.xauth_location, s->auth_display);
1242e73e9afaSDag-Erling Smørgrav 			fprintf(stderr,
1243e73e9afaSDag-Erling Smørgrav 			    "%.500s add %.100s %.100s %.100s\n",
1244af12a3e7SDag-Erling Smørgrav 			    options.xauth_location, s->auth_display,
1245ca3176e7SBrian Feldman 			    s->auth_proto, s->auth_data);
1246db1cb46cSKris Kennaway 		}
1247c2d3a559SKris Kennaway 		snprintf(cmd, sizeof cmd, "%s -q -",
1248c2d3a559SKris Kennaway 		    options.xauth_location);
1249c2d3a559SKris Kennaway 		f = popen(cmd, "w");
1250a04a10f8SKris Kennaway 		if (f) {
1251e73e9afaSDag-Erling Smørgrav 			fprintf(f, "remove %s\n",
1252e73e9afaSDag-Erling Smørgrav 			    s->auth_display);
1253af12a3e7SDag-Erling Smørgrav 			fprintf(f, "add %s %s %s\n",
1254af12a3e7SDag-Erling Smørgrav 			    s->auth_display, s->auth_proto,
1255ca3176e7SBrian Feldman 			    s->auth_data);
1256a04a10f8SKris Kennaway 			pclose(f);
1257c2d3a559SKris Kennaway 		} else {
1258c2d3a559SKris Kennaway 			fprintf(stderr, "Could not run %s\n",
1259c2d3a559SKris Kennaway 			    cmd);
1260a04a10f8SKris Kennaway 		}
1261a04a10f8SKris Kennaway 	}
1262a04a10f8SKris Kennaway }
1263ca3176e7SBrian Feldman 
1264af12a3e7SDag-Erling Smørgrav static void
1265af12a3e7SDag-Erling Smørgrav do_nologin(struct passwd *pw)
1266af12a3e7SDag-Erling Smørgrav {
1267af12a3e7SDag-Erling Smørgrav 	FILE *f = NULL;
1268af12a3e7SDag-Erling Smørgrav 	char buf[1024];
1269af12a3e7SDag-Erling Smørgrav 
1270af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1271af12a3e7SDag-Erling Smørgrav 	if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid)
1272af12a3e7SDag-Erling Smørgrav 		f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN,
1273af12a3e7SDag-Erling Smørgrav 		    _PATH_NOLOGIN), "r");
1274af12a3e7SDag-Erling Smørgrav #else
1275af12a3e7SDag-Erling Smørgrav 	if (pw->pw_uid)
1276af12a3e7SDag-Erling Smørgrav 		f = fopen(_PATH_NOLOGIN, "r");
1277af12a3e7SDag-Erling Smørgrav #endif
1278af12a3e7SDag-Erling Smørgrav 	if (f) {
1279af12a3e7SDag-Erling Smørgrav 		/* /etc/nologin exists.  Print its contents and exit. */
1280cf2b5f3bSDag-Erling Smørgrav 		logit("User %.100s not allowed because %s exists",
1281f388f5efSDag-Erling Smørgrav 		    pw->pw_name, _PATH_NOLOGIN);
1282af12a3e7SDag-Erling Smørgrav 		while (fgets(buf, sizeof(buf), f))
1283af12a3e7SDag-Erling Smørgrav 			fputs(buf, stderr);
1284af12a3e7SDag-Erling Smørgrav 		fclose(f);
1285e73e9afaSDag-Erling Smørgrav 		fflush(NULL);
1286af12a3e7SDag-Erling Smørgrav 		exit(254);
1287af12a3e7SDag-Erling Smørgrav 	}
1288af12a3e7SDag-Erling Smørgrav }
1289af12a3e7SDag-Erling Smørgrav 
1290af12a3e7SDag-Erling Smørgrav /* Set login name, uid, gid, and groups. */
1291989dd127SDag-Erling Smørgrav void
129280628bacSDag-Erling Smørgrav do_setusercontext(struct passwd *pw)
1293af12a3e7SDag-Erling Smørgrav {
1294e73e9afaSDag-Erling Smørgrav #ifndef HAVE_CYGWIN
1295e73e9afaSDag-Erling Smørgrav 	if (getuid() == 0 || geteuid() == 0)
1296989dd127SDag-Erling Smørgrav #endif /* HAVE_CYGWIN */
1297e73e9afaSDag-Erling Smørgrav 	{
1298e73e9afaSDag-Erling Smørgrav 
1299989dd127SDag-Erling Smørgrav #ifdef HAVE_SETPCRED
1300cf2b5f3bSDag-Erling Smørgrav 		if (setpcred(pw->pw_name, (char **)NULL) == -1)
1301cf2b5f3bSDag-Erling Smørgrav 			fatal("Failed to set process credentials");
1302989dd127SDag-Erling Smørgrav #endif /* HAVE_SETPCRED */
1303989dd127SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1304a82e551fSDag-Erling Smørgrav # ifdef __bsdi__
1305a82e551fSDag-Erling Smørgrav 		setpgid(0, 0);
1306a82e551fSDag-Erling Smørgrav # endif
1307aa49c926SDag-Erling Smørgrav #ifdef GSSAPI
1308aa49c926SDag-Erling Smørgrav 		if (options.gss_authentication) {
1309aa49c926SDag-Erling Smørgrav 			temporarily_use_uid(pw);
1310aa49c926SDag-Erling Smørgrav 			ssh_gssapi_storecreds();
1311aa49c926SDag-Erling Smørgrav 			restore_uid();
1312aa49c926SDag-Erling Smørgrav 		}
1313aa49c926SDag-Erling Smørgrav #endif
13141ec0d754SDag-Erling Smørgrav # ifdef USE_PAM
13151ec0d754SDag-Erling Smørgrav 		if (options.use_pam) {
13161ec0d754SDag-Erling Smørgrav 			do_pam_session();
13171ec0d754SDag-Erling Smørgrav 			do_pam_setcred(0);
13181ec0d754SDag-Erling Smørgrav 		}
13191ec0d754SDag-Erling Smørgrav # endif /* USE_PAM */
1320989dd127SDag-Erling Smørgrav 		if (setusercontext(lc, pw, pw->pw_uid,
1321c62005fcSDag-Erling Smørgrav 		    (LOGIN_SETALL & ~(LOGIN_SETENV|LOGIN_SETPATH))) < 0) {
1322989dd127SDag-Erling Smørgrav 			perror("unable to set user context");
1323989dd127SDag-Erling Smørgrav 			exit(1);
1324989dd127SDag-Erling Smørgrav 		}
1325989dd127SDag-Erling Smørgrav #else
1326989dd127SDag-Erling Smørgrav # if defined(HAVE_GETLUID) && defined(HAVE_SETLUID)
1327989dd127SDag-Erling Smørgrav 		/* Sets login uid for accounting */
1328989dd127SDag-Erling Smørgrav 		if (getluid() == -1 && setluid(pw->pw_uid) == -1)
1329989dd127SDag-Erling Smørgrav 			error("setluid: %s", strerror(errno));
1330989dd127SDag-Erling Smørgrav # endif /* defined(HAVE_GETLUID) && defined(HAVE_SETLUID) */
1331989dd127SDag-Erling Smørgrav 
1332af12a3e7SDag-Erling Smørgrav 		if (setlogin(pw->pw_name) < 0)
1333af12a3e7SDag-Erling Smørgrav 			error("setlogin failed: %s", strerror(errno));
1334af12a3e7SDag-Erling Smørgrav 		if (setgid(pw->pw_gid) < 0) {
1335af12a3e7SDag-Erling Smørgrav 			perror("setgid");
1336af12a3e7SDag-Erling Smørgrav 			exit(1);
1337af12a3e7SDag-Erling Smørgrav 		}
1338af12a3e7SDag-Erling Smørgrav 		/* Initialize the group list. */
1339af12a3e7SDag-Erling Smørgrav 		if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
1340af12a3e7SDag-Erling Smørgrav 			perror("initgroups");
1341af12a3e7SDag-Erling Smørgrav 			exit(1);
1342af12a3e7SDag-Erling Smørgrav 		}
1343af12a3e7SDag-Erling Smørgrav 		endgrent();
1344aa49c926SDag-Erling Smørgrav #ifdef GSSAPI
1345aa49c926SDag-Erling Smørgrav 		if (options.gss_authentication) {
1346aa49c926SDag-Erling Smørgrav 			temporarily_use_uid(pw);
1347aa49c926SDag-Erling Smørgrav 			ssh_gssapi_storecreds();
1348aa49c926SDag-Erling Smørgrav 			restore_uid();
1349aa49c926SDag-Erling Smørgrav 		}
1350aa49c926SDag-Erling Smørgrav #endif
1351989dd127SDag-Erling Smørgrav # ifdef USE_PAM
1352989dd127SDag-Erling Smørgrav 		/*
1353989dd127SDag-Erling Smørgrav 		 * PAM credentials may take the form of supplementary groups.
1354989dd127SDag-Erling Smørgrav 		 * These will have been wiped by the above initgroups() call.
1355989dd127SDag-Erling Smørgrav 		 * Reestablish them here.
1356989dd127SDag-Erling Smørgrav 		 */
1357cf2b5f3bSDag-Erling Smørgrav 		if (options.use_pam) {
1358cf2b5f3bSDag-Erling Smørgrav 			do_pam_session();
1359989dd127SDag-Erling Smørgrav 			do_pam_setcred(0);
1360cf2b5f3bSDag-Erling Smørgrav 		}
1361989dd127SDag-Erling Smørgrav # endif /* USE_PAM */
1362989dd127SDag-Erling Smørgrav # if defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY)
1363989dd127SDag-Erling Smørgrav 		irix_setusercontext(pw);
1364989dd127SDag-Erling Smørgrav #  endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */
1365a82e551fSDag-Erling Smørgrav # ifdef _AIX
1366f388f5efSDag-Erling Smørgrav 		aix_usrinfo(pw);
1367a82e551fSDag-Erling Smørgrav # endif /* _AIX */
1368d4ecd108SDag-Erling Smørgrav #if defined(HAVE_LIBIAF)  &&  !defined(BROKEN_LIBIAF)
1369d4ecd108SDag-Erling Smørgrav 		if (set_id(pw->pw_name) != 0) {
1370d4ecd108SDag-Erling Smørgrav 			exit(1);
1371d4ecd108SDag-Erling Smørgrav 		}
1372d4ecd108SDag-Erling Smørgrav #endif /* HAVE_LIBIAF  && !BROKEN_LIBIAF */
1373af12a3e7SDag-Erling Smørgrav 		/* Permanently switch to the desired uid. */
1374af12a3e7SDag-Erling Smørgrav 		permanently_set_uid(pw);
1375989dd127SDag-Erling Smørgrav #endif
1376af12a3e7SDag-Erling Smørgrav 	}
1377e73e9afaSDag-Erling Smørgrav 
1378e73e9afaSDag-Erling Smørgrav #ifdef HAVE_CYGWIN
1379e73e9afaSDag-Erling Smørgrav 	if (is_winnt)
1380e73e9afaSDag-Erling Smørgrav #endif
1381af12a3e7SDag-Erling Smørgrav 	if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
1382af12a3e7SDag-Erling Smørgrav 		fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
138380628bacSDag-Erling Smørgrav }
138480628bacSDag-Erling Smørgrav 
138580628bacSDag-Erling Smørgrav static void
13861ec0d754SDag-Erling Smørgrav do_pwchange(Session *s)
13871ec0d754SDag-Erling Smørgrav {
138821e764dfSDag-Erling Smørgrav 	fflush(NULL);
13891ec0d754SDag-Erling Smørgrav 	fprintf(stderr, "WARNING: Your password has expired.\n");
13901ec0d754SDag-Erling Smørgrav 	if (s->ttyfd != -1) {
13911ec0d754SDag-Erling Smørgrav 		fprintf(stderr,
13921ec0d754SDag-Erling Smørgrav 		    "You must change your password now and login again!\n");
1393aa49c926SDag-Erling Smørgrav #ifdef PASSWD_NEEDS_USERNAME
1394aa49c926SDag-Erling Smørgrav 		execl(_PATH_PASSWD_PROG, "passwd", s->pw->pw_name,
1395aa49c926SDag-Erling Smørgrav 		    (char *)NULL);
1396aa49c926SDag-Erling Smørgrav #else
13971ec0d754SDag-Erling Smørgrav 		execl(_PATH_PASSWD_PROG, "passwd", (char *)NULL);
1398aa49c926SDag-Erling Smørgrav #endif
13991ec0d754SDag-Erling Smørgrav 		perror("passwd");
14001ec0d754SDag-Erling Smørgrav 	} else {
14011ec0d754SDag-Erling Smørgrav 		fprintf(stderr,
14021ec0d754SDag-Erling Smørgrav 		    "Password change required but no TTY available.\n");
14031ec0d754SDag-Erling Smørgrav 	}
14041ec0d754SDag-Erling Smørgrav 	exit(1);
14051ec0d754SDag-Erling Smørgrav }
14061ec0d754SDag-Erling Smørgrav 
14071ec0d754SDag-Erling Smørgrav static void
140880628bacSDag-Erling Smørgrav launch_login(struct passwd *pw, const char *hostname)
140980628bacSDag-Erling Smørgrav {
141080628bacSDag-Erling Smørgrav 	/* Launch login(1). */
141180628bacSDag-Erling Smørgrav 
1412989dd127SDag-Erling Smørgrav 	execl(LOGIN_PROGRAM, "login", "-h", hostname,
1413989dd127SDag-Erling Smørgrav #ifdef xxxLOGIN_NEEDS_TERM
1414989dd127SDag-Erling Smørgrav 		    (s->term ? s->term : "unknown"),
1415989dd127SDag-Erling Smørgrav #endif /* LOGIN_NEEDS_TERM */
1416989dd127SDag-Erling Smørgrav #ifdef LOGIN_NO_ENDOPT
1417989dd127SDag-Erling Smørgrav 	    "-p", "-f", pw->pw_name, (char *)NULL);
1418989dd127SDag-Erling Smørgrav #else
141980628bacSDag-Erling Smørgrav 	    "-p", "-f", "--", pw->pw_name, (char *)NULL);
1420989dd127SDag-Erling Smørgrav #endif
142180628bacSDag-Erling Smørgrav 
142280628bacSDag-Erling Smørgrav 	/* Login couldn't be executed, die. */
142380628bacSDag-Erling Smørgrav 
142480628bacSDag-Erling Smørgrav 	perror("login");
142580628bacSDag-Erling Smørgrav 	exit(1);
1426af12a3e7SDag-Erling Smørgrav }
1427af12a3e7SDag-Erling Smørgrav 
14281ec0d754SDag-Erling Smørgrav static void
14291ec0d754SDag-Erling Smørgrav child_close_fds(void)
14301ec0d754SDag-Erling Smørgrav {
14311ec0d754SDag-Erling Smørgrav 	int i;
14321ec0d754SDag-Erling Smørgrav 
14331ec0d754SDag-Erling Smørgrav 	if (packet_get_connection_in() == packet_get_connection_out())
14341ec0d754SDag-Erling Smørgrav 		close(packet_get_connection_in());
14351ec0d754SDag-Erling Smørgrav 	else {
14361ec0d754SDag-Erling Smørgrav 		close(packet_get_connection_in());
14371ec0d754SDag-Erling Smørgrav 		close(packet_get_connection_out());
14381ec0d754SDag-Erling Smørgrav 	}
14391ec0d754SDag-Erling Smørgrav 	/*
14401ec0d754SDag-Erling Smørgrav 	 * Close all descriptors related to channels.  They will still remain
14411ec0d754SDag-Erling Smørgrav 	 * open in the parent.
14421ec0d754SDag-Erling Smørgrav 	 */
14431ec0d754SDag-Erling Smørgrav 	/* XXX better use close-on-exec? -markus */
14441ec0d754SDag-Erling Smørgrav 	channel_close_all();
14451ec0d754SDag-Erling Smørgrav 
14461ec0d754SDag-Erling Smørgrav 	/*
14471ec0d754SDag-Erling Smørgrav 	 * Close any extra file descriptors.  Note that there may still be
14481ec0d754SDag-Erling Smørgrav 	 * descriptors left by system functions.  They will be closed later.
14491ec0d754SDag-Erling Smørgrav 	 */
14501ec0d754SDag-Erling Smørgrav 	endpwent();
14511ec0d754SDag-Erling Smørgrav 
14521ec0d754SDag-Erling Smørgrav 	/*
14531ec0d754SDag-Erling Smørgrav 	 * Close any extra open file descriptors so that we don\'t have them
14541ec0d754SDag-Erling Smørgrav 	 * hanging around in clients.  Note that we want to do this after
14551ec0d754SDag-Erling Smørgrav 	 * initgroups, because at least on Solaris 2.3 it leaves file
14561ec0d754SDag-Erling Smørgrav 	 * descriptors open.
14571ec0d754SDag-Erling Smørgrav 	 */
14581ec0d754SDag-Erling Smørgrav 	for (i = 3; i < 64; i++)
14591ec0d754SDag-Erling Smørgrav 		close(i);
14601ec0d754SDag-Erling Smørgrav }
14611ec0d754SDag-Erling Smørgrav 
1462af12a3e7SDag-Erling Smørgrav /*
1463af12a3e7SDag-Erling Smørgrav  * Performs common processing for the child, such as setting up the
1464af12a3e7SDag-Erling Smørgrav  * environment, closing extra file descriptors, setting the user and group
1465af12a3e7SDag-Erling Smørgrav  * ids, and executing the command or shell.
1466af12a3e7SDag-Erling Smørgrav  */
1467af12a3e7SDag-Erling Smørgrav void
1468af12a3e7SDag-Erling Smørgrav do_child(Session *s, const char *command)
1469af12a3e7SDag-Erling Smørgrav {
1470af12a3e7SDag-Erling Smørgrav 	extern char **environ;
1471989dd127SDag-Erling Smørgrav 	char **env;
1472af12a3e7SDag-Erling Smørgrav 	char *argv[10];
1473af12a3e7SDag-Erling Smørgrav 	const char *shell, *shell0, *hostname = NULL;
1474af12a3e7SDag-Erling Smørgrav 	struct passwd *pw = s->pw;
1475bccd7616SAndrey A. Chernov #ifdef HAVE_LOGIN_CAP
1476bccd7616SAndrey A. Chernov 	int lc_requirehome;
1477bccd7616SAndrey A. Chernov #endif
1478af12a3e7SDag-Erling Smørgrav 
1479af12a3e7SDag-Erling Smørgrav 	/* remove hostkey from the child's memory */
1480af12a3e7SDag-Erling Smørgrav 	destroy_sensitive_data();
1481af12a3e7SDag-Erling Smørgrav 
14821ec0d754SDag-Erling Smørgrav 	/* Force a password change */
14831ec0d754SDag-Erling Smørgrav 	if (s->authctxt->force_pwchange) {
14841ec0d754SDag-Erling Smørgrav 		do_setusercontext(pw);
14851ec0d754SDag-Erling Smørgrav 		child_close_fds();
14861ec0d754SDag-Erling Smørgrav 		do_pwchange(s);
14871ec0d754SDag-Erling Smørgrav 		exit(1);
14881ec0d754SDag-Erling Smørgrav 	}
14891ec0d754SDag-Erling Smørgrav 
1490af12a3e7SDag-Erling Smørgrav 	/* login(1) is only called if we execute the login shell */
1491af12a3e7SDag-Erling Smørgrav 	if (options.use_login && command != NULL)
1492af12a3e7SDag-Erling Smørgrav 		options.use_login = 0;
1493af12a3e7SDag-Erling Smørgrav 
1494f388f5efSDag-Erling Smørgrav #ifdef _UNICOS
1495f388f5efSDag-Erling Smørgrav 	cray_setup(pw->pw_uid, pw->pw_name, command);
1496f388f5efSDag-Erling Smørgrav #endif /* _UNICOS */
1497f388f5efSDag-Erling Smørgrav 
1498af12a3e7SDag-Erling Smørgrav 	/*
1499af12a3e7SDag-Erling Smørgrav 	 * Login(1) does this as well, and it needs uid 0 for the "-h"
1500af12a3e7SDag-Erling Smørgrav 	 * switch, so we let login(1) to this for us.
1501af12a3e7SDag-Erling Smørgrav 	 */
1502af12a3e7SDag-Erling Smørgrav 	if (!options.use_login) {
1503989dd127SDag-Erling Smørgrav #ifdef HAVE_OSF_SIA
1504e73e9afaSDag-Erling Smørgrav 		session_setup_sia(pw, s->ttyfd == -1 ? NULL : s->tty);
1505989dd127SDag-Erling Smørgrav 		if (!check_quietlogin(s, command))
1506989dd127SDag-Erling Smørgrav 			do_motd();
1507989dd127SDag-Erling Smørgrav #else /* HAVE_OSF_SIA */
1508af12a3e7SDag-Erling Smørgrav 		do_nologin(pw);
1509989dd127SDag-Erling Smørgrav 		do_setusercontext(pw);
151021e764dfSDag-Erling Smørgrav 		/*
151121e764dfSDag-Erling Smørgrav 		 * PAM session modules in do_setusercontext may have
151221e764dfSDag-Erling Smørgrav 		 * generated messages, so if this in an interactive
151321e764dfSDag-Erling Smørgrav 		 * login then display them too.
151421e764dfSDag-Erling Smørgrav 		 */
1515aa49c926SDag-Erling Smørgrav 		if (!check_quietlogin(s, command))
151621e764dfSDag-Erling Smørgrav 			display_loginmsg();
1517989dd127SDag-Erling Smørgrav #endif /* HAVE_OSF_SIA */
1518af12a3e7SDag-Erling Smørgrav 	}
1519af12a3e7SDag-Erling Smørgrav 
1520aa49c926SDag-Erling Smørgrav #ifdef USE_PAM
1521aa49c926SDag-Erling Smørgrav 	if (options.use_pam && !options.use_login && !is_pam_session_open()) {
1522aa49c926SDag-Erling Smørgrav 		debug3("PAM session not opened, exiting");
1523aa49c926SDag-Erling Smørgrav 		display_loginmsg();
1524aa49c926SDag-Erling Smørgrav 		exit(254);
1525aa49c926SDag-Erling Smørgrav 	}
1526aa49c926SDag-Erling Smørgrav #endif
1527aa49c926SDag-Erling Smørgrav 
1528af12a3e7SDag-Erling Smørgrav 	/*
1529af12a3e7SDag-Erling Smørgrav 	 * Get the shell from the password data.  An empty shell field is
1530af12a3e7SDag-Erling Smørgrav 	 * legal, and means /bin/sh.
1531af12a3e7SDag-Erling Smørgrav 	 */
1532af12a3e7SDag-Erling Smørgrav 	shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
1533e73e9afaSDag-Erling Smørgrav 
1534e73e9afaSDag-Erling Smørgrav 	/*
1535e73e9afaSDag-Erling Smørgrav 	 * Make sure $SHELL points to the shell from the password file,
1536e73e9afaSDag-Erling Smørgrav 	 * even if shell is overridden from login.conf
1537e73e9afaSDag-Erling Smørgrav 	 */
1538e73e9afaSDag-Erling Smørgrav 	env = do_setup_env(s, shell);
1539e73e9afaSDag-Erling Smørgrav 
1540af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1541af12a3e7SDag-Erling Smørgrav 	shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);
1542af12a3e7SDag-Erling Smørgrav #endif
1543af12a3e7SDag-Erling Smørgrav 
1544af12a3e7SDag-Erling Smørgrav 	/* we have to stash the hostname before we close our socket. */
1545af12a3e7SDag-Erling Smørgrav 	if (options.use_login)
1546af12a3e7SDag-Erling Smørgrav 		hostname = get_remote_name_or_ip(utmp_len,
1547cf2b5f3bSDag-Erling Smørgrav 		    options.use_dns);
1548af12a3e7SDag-Erling Smørgrav 	/*
1549af12a3e7SDag-Erling Smørgrav 	 * Close the connection descriptors; note that this is the child, and
1550af12a3e7SDag-Erling Smørgrav 	 * the server will still have the socket open, and it is important
1551af12a3e7SDag-Erling Smørgrav 	 * that we do not shutdown it.  Note that the descriptors cannot be
1552af12a3e7SDag-Erling Smørgrav 	 * closed before building the environment, as we call
1553af12a3e7SDag-Erling Smørgrav 	 * get_remote_ipaddr there.
1554af12a3e7SDag-Erling Smørgrav 	 */
15551ec0d754SDag-Erling Smørgrav 	child_close_fds();
1556af12a3e7SDag-Erling Smørgrav 
1557af12a3e7SDag-Erling Smørgrav 	/*
1558af12a3e7SDag-Erling Smørgrav 	 * Must take new environment into use so that .ssh/rc,
1559af12a3e7SDag-Erling Smørgrav 	 * /etc/ssh/sshrc and xauth are run in the proper environment.
1560af12a3e7SDag-Erling Smørgrav 	 */
1561af12a3e7SDag-Erling Smørgrav 	environ = env;
1562af12a3e7SDag-Erling Smørgrav 
15631ec0d754SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
15641ec0d754SDag-Erling Smørgrav 	lc_requirehome = login_getcapbool(lc, "requirehome", 0);
15651ec0d754SDag-Erling Smørgrav 	login_close(lc);
15661ec0d754SDag-Erling Smørgrav #endif
15671ec0d754SDag-Erling Smørgrav #if defined(KRB5) && defined(USE_AFS)
15681ec0d754SDag-Erling Smørgrav 	/*
15691ec0d754SDag-Erling Smørgrav 	 * At this point, we check to see if AFS is active and if we have
15701ec0d754SDag-Erling Smørgrav 	 * a valid Kerberos 5 TGT. If so, it seems like a good idea to see
15711ec0d754SDag-Erling Smørgrav 	 * if we can (and need to) extend the ticket into an AFS token. If
15721ec0d754SDag-Erling Smørgrav 	 * we don't do this, we run into potential problems if the user's
15731ec0d754SDag-Erling Smørgrav 	 * home directory is in AFS and it's not world-readable.
15741ec0d754SDag-Erling Smørgrav 	 */
15751ec0d754SDag-Erling Smørgrav 
15761ec0d754SDag-Erling Smørgrav 	if (options.kerberos_get_afs_token && k_hasafs() &&
15771ec0d754SDag-Erling Smørgrav 	    (s->authctxt->krb5_ctx != NULL)) {
15781ec0d754SDag-Erling Smørgrav 		char cell[64];
15791ec0d754SDag-Erling Smørgrav 
15801ec0d754SDag-Erling Smørgrav 		debug("Getting AFS token");
15811ec0d754SDag-Erling Smørgrav 
15821ec0d754SDag-Erling Smørgrav 		k_setpag();
15831ec0d754SDag-Erling Smørgrav 
15841ec0d754SDag-Erling Smørgrav 		if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
15851ec0d754SDag-Erling Smørgrav 			krb5_afslog(s->authctxt->krb5_ctx,
15861ec0d754SDag-Erling Smørgrav 			    s->authctxt->krb5_fwd_ccache, cell, NULL);
15871ec0d754SDag-Erling Smørgrav 
15881ec0d754SDag-Erling Smørgrav 		krb5_afslog_home(s->authctxt->krb5_ctx,
15891ec0d754SDag-Erling Smørgrav 		    s->authctxt->krb5_fwd_ccache, NULL, NULL, pw->pw_dir);
15901ec0d754SDag-Erling Smørgrav 	}
15911ec0d754SDag-Erling Smørgrav #endif
15921ec0d754SDag-Erling Smørgrav 
1593af12a3e7SDag-Erling Smørgrav 	/* Change current directory to the user\'s home directory. */
1594af12a3e7SDag-Erling Smørgrav 	if (chdir(pw->pw_dir) < 0) {
1595af12a3e7SDag-Erling Smørgrav 		fprintf(stderr, "Could not chdir to home directory %s: %s\n",
1596af12a3e7SDag-Erling Smørgrav 		    pw->pw_dir, strerror(errno));
1597af12a3e7SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP
1598bccd7616SAndrey A. Chernov 		if (lc_requirehome)
1599af12a3e7SDag-Erling Smørgrav 			exit(1);
1600af12a3e7SDag-Erling Smørgrav #endif
1601af12a3e7SDag-Erling Smørgrav 	}
1602af12a3e7SDag-Erling Smørgrav 
1603af12a3e7SDag-Erling Smørgrav 	if (!options.use_login)
1604af12a3e7SDag-Erling Smørgrav 		do_rc_files(s, shell);
1605af12a3e7SDag-Erling Smørgrav 
1606ca3176e7SBrian Feldman 	/* restore SIGPIPE for child */
1607ca3176e7SBrian Feldman 	signal(SIGPIPE,  SIG_DFL);
1608ca3176e7SBrian Feldman 
1609af12a3e7SDag-Erling Smørgrav 	if (options.use_login) {
161080628bacSDag-Erling Smørgrav 		launch_login(pw, hostname);
161180628bacSDag-Erling Smørgrav 		/* NEVERREACHED */
1612af12a3e7SDag-Erling Smørgrav 	}
1613af12a3e7SDag-Erling Smørgrav 
1614af12a3e7SDag-Erling Smørgrav 	/* Get the last component of the shell name. */
1615af12a3e7SDag-Erling Smørgrav 	if ((shell0 = strrchr(shell, '/')) != NULL)
1616af12a3e7SDag-Erling Smørgrav 		shell0++;
1617af12a3e7SDag-Erling Smørgrav 	else
1618af12a3e7SDag-Erling Smørgrav 		shell0 = shell;
1619af12a3e7SDag-Erling Smørgrav 
1620a04a10f8SKris Kennaway 	/*
1621a04a10f8SKris Kennaway 	 * If we have no command, execute the shell.  In this case, the shell
1622a04a10f8SKris Kennaway 	 * name to be passed in argv[0] is preceded by '-' to indicate that
1623a04a10f8SKris Kennaway 	 * this is a login shell.
1624a04a10f8SKris Kennaway 	 */
1625a04a10f8SKris Kennaway 	if (!command) {
1626af12a3e7SDag-Erling Smørgrav 		char argv0[256];
1627a04a10f8SKris Kennaway 
1628a04a10f8SKris Kennaway 		/* Start the shell.  Set initial character to '-'. */
1629af12a3e7SDag-Erling Smørgrav 		argv0[0] = '-';
1630af12a3e7SDag-Erling Smørgrav 
1631af12a3e7SDag-Erling Smørgrav 		if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1)
1632af12a3e7SDag-Erling Smørgrav 		    >= sizeof(argv0) - 1) {
1633af12a3e7SDag-Erling Smørgrav 			errno = EINVAL;
1634af12a3e7SDag-Erling Smørgrav 			perror(shell);
1635af12a3e7SDag-Erling Smørgrav 			exit(1);
1636af12a3e7SDag-Erling Smørgrav 		}
1637a04a10f8SKris Kennaway 
1638a04a10f8SKris Kennaway 		/* Execute the shell. */
1639af12a3e7SDag-Erling Smørgrav 		argv[0] = argv0;
1640a04a10f8SKris Kennaway 		argv[1] = NULL;
1641a04a10f8SKris Kennaway 		execve(shell, argv, env);
1642a04a10f8SKris Kennaway 
1643a04a10f8SKris Kennaway 		/* Executing the shell failed. */
1644a04a10f8SKris Kennaway 		perror(shell);
1645a04a10f8SKris Kennaway 		exit(1);
1646a04a10f8SKris Kennaway 	}
1647a04a10f8SKris Kennaway 	/*
1648a04a10f8SKris Kennaway 	 * Execute the command using the user's shell.  This uses the -c
1649a04a10f8SKris Kennaway 	 * option to execute the command.
1650a04a10f8SKris Kennaway 	 */
1651af12a3e7SDag-Erling Smørgrav 	argv[0] = (char *) shell0;
1652a04a10f8SKris Kennaway 	argv[1] = "-c";
1653a04a10f8SKris Kennaway 	argv[2] = (char *) command;
1654a04a10f8SKris Kennaway 	argv[3] = NULL;
1655a04a10f8SKris Kennaway 	execve(shell, argv, env);
1656a04a10f8SKris Kennaway 	perror(shell);
1657a04a10f8SKris Kennaway 	exit(1);
1658a04a10f8SKris Kennaway }
1659a04a10f8SKris Kennaway 
1660a04a10f8SKris Kennaway Session *
1661a04a10f8SKris Kennaway session_new(void)
1662a04a10f8SKris Kennaway {
1663a04a10f8SKris Kennaway 	int i;
1664a04a10f8SKris Kennaway 	static int did_init = 0;
1665a04a10f8SKris Kennaway 	if (!did_init) {
1666a04a10f8SKris Kennaway 		debug("session_new: init");
1667a04a10f8SKris Kennaway 		for (i = 0; i < MAX_SESSIONS; i++) {
1668a04a10f8SKris Kennaway 			sessions[i].used = 0;
1669a04a10f8SKris Kennaway 		}
1670a04a10f8SKris Kennaway 		did_init = 1;
1671a04a10f8SKris Kennaway 	}
1672a04a10f8SKris Kennaway 	for (i = 0; i < MAX_SESSIONS; i++) {
1673a04a10f8SKris Kennaway 		Session *s = &sessions[i];
1674a04a10f8SKris Kennaway 		if (! s->used) {
1675ca3176e7SBrian Feldman 			memset(s, 0, sizeof(*s));
1676a04a10f8SKris Kennaway 			s->chanid = -1;
1677a04a10f8SKris Kennaway 			s->ptyfd = -1;
1678a04a10f8SKris Kennaway 			s->ttyfd = -1;
1679a04a10f8SKris Kennaway 			s->used = 1;
1680af12a3e7SDag-Erling Smørgrav 			s->self = i;
1681d4ecd108SDag-Erling Smørgrav 			s->x11_chanids = NULL;
1682a04a10f8SKris Kennaway 			debug("session_new: session %d", i);
1683a04a10f8SKris Kennaway 			return s;
1684a04a10f8SKris Kennaway 		}
1685a04a10f8SKris Kennaway 	}
1686a04a10f8SKris Kennaway 	return NULL;
1687a04a10f8SKris Kennaway }
1688a04a10f8SKris Kennaway 
1689af12a3e7SDag-Erling Smørgrav static void
1690a04a10f8SKris Kennaway session_dump(void)
1691a04a10f8SKris Kennaway {
1692a04a10f8SKris Kennaway 	int i;
1693a04a10f8SKris Kennaway 	for (i = 0; i < MAX_SESSIONS; i++) {
1694a04a10f8SKris Kennaway 		Session *s = &sessions[i];
169580628bacSDag-Erling Smørgrav 		debug("dump: used %d session %d %p channel %d pid %ld",
1696a04a10f8SKris Kennaway 		    s->used,
1697a04a10f8SKris Kennaway 		    s->self,
1698a04a10f8SKris Kennaway 		    s,
1699a04a10f8SKris Kennaway 		    s->chanid,
170080628bacSDag-Erling Smørgrav 		    (long)s->pid);
1701a04a10f8SKris Kennaway 	}
1702a04a10f8SKris Kennaway }
1703a04a10f8SKris Kennaway 
1704a04a10f8SKris Kennaway int
1705af12a3e7SDag-Erling Smørgrav session_open(Authctxt *authctxt, int chanid)
1706a04a10f8SKris Kennaway {
1707a04a10f8SKris Kennaway 	Session *s = session_new();
1708a04a10f8SKris Kennaway 	debug("session_open: channel %d", chanid);
1709a04a10f8SKris Kennaway 	if (s == NULL) {
1710a04a10f8SKris Kennaway 		error("no more sessions");
1711a04a10f8SKris Kennaway 		return 0;
1712a04a10f8SKris Kennaway 	}
1713af12a3e7SDag-Erling Smørgrav 	s->authctxt = authctxt;
1714af12a3e7SDag-Erling Smørgrav 	s->pw = authctxt->pw;
17151ec0d754SDag-Erling Smørgrav 	if (s->pw == NULL || !authctxt->valid)
1716ca3176e7SBrian Feldman 		fatal("no user for session %d", s->self);
1717a04a10f8SKris Kennaway 	debug("session_open: session %d: link with channel %d", s->self, chanid);
1718a04a10f8SKris Kennaway 	s->chanid = chanid;
1719a04a10f8SKris Kennaway 	return 1;
1720a04a10f8SKris Kennaway }
1721a04a10f8SKris Kennaway 
172280628bacSDag-Erling Smørgrav Session *
172380628bacSDag-Erling Smørgrav session_by_tty(char *tty)
172480628bacSDag-Erling Smørgrav {
172580628bacSDag-Erling Smørgrav 	int i;
172680628bacSDag-Erling Smørgrav 	for (i = 0; i < MAX_SESSIONS; i++) {
172780628bacSDag-Erling Smørgrav 		Session *s = &sessions[i];
172880628bacSDag-Erling Smørgrav 		if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) {
172980628bacSDag-Erling Smørgrav 			debug("session_by_tty: session %d tty %s", i, tty);
173080628bacSDag-Erling Smørgrav 			return s;
173180628bacSDag-Erling Smørgrav 		}
173280628bacSDag-Erling Smørgrav 	}
173380628bacSDag-Erling Smørgrav 	debug("session_by_tty: unknown tty %.100s", tty);
173480628bacSDag-Erling Smørgrav 	session_dump();
173580628bacSDag-Erling Smørgrav 	return NULL;
173680628bacSDag-Erling Smørgrav }
173780628bacSDag-Erling Smørgrav 
1738af12a3e7SDag-Erling Smørgrav static Session *
1739a04a10f8SKris Kennaway session_by_channel(int id)
1740a04a10f8SKris Kennaway {
1741a04a10f8SKris Kennaway 	int i;
1742a04a10f8SKris Kennaway 	for (i = 0; i < MAX_SESSIONS; i++) {
1743a04a10f8SKris Kennaway 		Session *s = &sessions[i];
1744a04a10f8SKris Kennaway 		if (s->used && s->chanid == id) {
1745a04a10f8SKris Kennaway 			debug("session_by_channel: session %d channel %d", i, id);
1746a04a10f8SKris Kennaway 			return s;
1747a04a10f8SKris Kennaway 		}
1748a04a10f8SKris Kennaway 	}
1749a04a10f8SKris Kennaway 	debug("session_by_channel: unknown channel %d", id);
1750a04a10f8SKris Kennaway 	session_dump();
1751a04a10f8SKris Kennaway 	return NULL;
1752a04a10f8SKris Kennaway }
1753a04a10f8SKris Kennaway 
1754af12a3e7SDag-Erling Smørgrav static Session *
1755d4ecd108SDag-Erling Smørgrav session_by_x11_channel(int id)
1756d4ecd108SDag-Erling Smørgrav {
1757d4ecd108SDag-Erling Smørgrav 	int i, j;
1758d4ecd108SDag-Erling Smørgrav 
1759d4ecd108SDag-Erling Smørgrav 	for (i = 0; i < MAX_SESSIONS; i++) {
1760d4ecd108SDag-Erling Smørgrav 		Session *s = &sessions[i];
1761d4ecd108SDag-Erling Smørgrav 
1762d4ecd108SDag-Erling Smørgrav 		if (s->x11_chanids == NULL || !s->used)
1763d4ecd108SDag-Erling Smørgrav 			continue;
1764d4ecd108SDag-Erling Smørgrav 		for (j = 0; s->x11_chanids[j] != -1; j++) {
1765d4ecd108SDag-Erling Smørgrav 			if (s->x11_chanids[j] == id) {
1766d4ecd108SDag-Erling Smørgrav 				debug("session_by_x11_channel: session %d "
1767d4ecd108SDag-Erling Smørgrav 				    "channel %d", s->self, id);
1768d4ecd108SDag-Erling Smørgrav 				return s;
1769d4ecd108SDag-Erling Smørgrav 			}
1770d4ecd108SDag-Erling Smørgrav 		}
1771d4ecd108SDag-Erling Smørgrav 	}
1772d4ecd108SDag-Erling Smørgrav 	debug("session_by_x11_channel: unknown channel %d", id);
1773d4ecd108SDag-Erling Smørgrav 	session_dump();
1774d4ecd108SDag-Erling Smørgrav 	return NULL;
1775d4ecd108SDag-Erling Smørgrav }
1776d4ecd108SDag-Erling Smørgrav 
1777d4ecd108SDag-Erling Smørgrav static Session *
1778a04a10f8SKris Kennaway session_by_pid(pid_t pid)
1779a04a10f8SKris Kennaway {
1780a04a10f8SKris Kennaway 	int i;
178180628bacSDag-Erling Smørgrav 	debug("session_by_pid: pid %ld", (long)pid);
1782a04a10f8SKris Kennaway 	for (i = 0; i < MAX_SESSIONS; i++) {
1783a04a10f8SKris Kennaway 		Session *s = &sessions[i];
1784a04a10f8SKris Kennaway 		if (s->used && s->pid == pid)
1785a04a10f8SKris Kennaway 			return s;
1786a04a10f8SKris Kennaway 	}
178780628bacSDag-Erling Smørgrav 	error("session_by_pid: unknown pid %ld", (long)pid);
1788a04a10f8SKris Kennaway 	session_dump();
1789a04a10f8SKris Kennaway 	return NULL;
1790a04a10f8SKris Kennaway }
1791a04a10f8SKris Kennaway 
1792af12a3e7SDag-Erling Smørgrav static int
1793a04a10f8SKris Kennaway session_window_change_req(Session *s)
1794a04a10f8SKris Kennaway {
1795a04a10f8SKris Kennaway 	s->col = packet_get_int();
1796a04a10f8SKris Kennaway 	s->row = packet_get_int();
1797a04a10f8SKris Kennaway 	s->xpixel = packet_get_int();
1798a04a10f8SKris Kennaway 	s->ypixel = packet_get_int();
1799af12a3e7SDag-Erling Smørgrav 	packet_check_eom();
1800a04a10f8SKris Kennaway 	pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
1801a04a10f8SKris Kennaway 	return 1;
1802a04a10f8SKris Kennaway }
1803a04a10f8SKris Kennaway 
1804af12a3e7SDag-Erling Smørgrav static int
1805a04a10f8SKris Kennaway session_pty_req(Session *s)
1806a04a10f8SKris Kennaway {
1807ca3176e7SBrian Feldman 	u_int len;
1808ca3176e7SBrian Feldman 	int n_bytes;
1809a04a10f8SKris Kennaway 
1810af12a3e7SDag-Erling Smørgrav 	if (no_pty_flag) {
1811af12a3e7SDag-Erling Smørgrav 		debug("Allocating a pty not permitted for this authentication.");
1812c2d3a559SKris Kennaway 		return 0;
1813af12a3e7SDag-Erling Smørgrav 	}
1814af12a3e7SDag-Erling Smørgrav 	if (s->ttyfd != -1) {
1815af12a3e7SDag-Erling Smørgrav 		packet_disconnect("Protocol error: you already have a pty.");
1816a04a10f8SKris Kennaway 		return 0;
1817af12a3e7SDag-Erling Smørgrav 	}
1818af12a3e7SDag-Erling Smørgrav 
1819a04a10f8SKris Kennaway 	s->term = packet_get_string(&len);
1820af12a3e7SDag-Erling Smørgrav 
1821af12a3e7SDag-Erling Smørgrav 	if (compat20) {
1822a04a10f8SKris Kennaway 		s->col = packet_get_int();
1823a04a10f8SKris Kennaway 		s->row = packet_get_int();
1824af12a3e7SDag-Erling Smørgrav 	} else {
1825af12a3e7SDag-Erling Smørgrav 		s->row = packet_get_int();
1826af12a3e7SDag-Erling Smørgrav 		s->col = packet_get_int();
1827af12a3e7SDag-Erling Smørgrav 	}
1828a04a10f8SKris Kennaway 	s->xpixel = packet_get_int();
1829a04a10f8SKris Kennaway 	s->ypixel = packet_get_int();
1830a04a10f8SKris Kennaway 
1831a04a10f8SKris Kennaway 	if (strcmp(s->term, "") == 0) {
1832a04a10f8SKris Kennaway 		xfree(s->term);
1833a04a10f8SKris Kennaway 		s->term = NULL;
1834a04a10f8SKris Kennaway 	}
1835af12a3e7SDag-Erling Smørgrav 
1836a04a10f8SKris Kennaway 	/* Allocate a pty and open it. */
1837af12a3e7SDag-Erling Smørgrav 	debug("Allocating pty.");
183880628bacSDag-Erling Smørgrav 	if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)))) {
1839af12a3e7SDag-Erling Smørgrav 		if (s->term)
1840a04a10f8SKris Kennaway 			xfree(s->term);
1841a04a10f8SKris Kennaway 		s->term = NULL;
1842a04a10f8SKris Kennaway 		s->ptyfd = -1;
1843a04a10f8SKris Kennaway 		s->ttyfd = -1;
1844a04a10f8SKris Kennaway 		error("session_pty_req: session %d alloc failed", s->self);
1845a04a10f8SKris Kennaway 		return 0;
1846a04a10f8SKris Kennaway 	}
1847a04a10f8SKris Kennaway 	debug("session_pty_req: session %d alloc %s", s->self, s->tty);
1848af12a3e7SDag-Erling Smørgrav 
1849af12a3e7SDag-Erling Smørgrav 	/* for SSH1 the tty modes length is not given */
1850af12a3e7SDag-Erling Smørgrav 	if (!compat20)
1851af12a3e7SDag-Erling Smørgrav 		n_bytes = packet_remaining();
1852af12a3e7SDag-Erling Smørgrav 	tty_parse_modes(s->ttyfd, &n_bytes);
1853af12a3e7SDag-Erling Smørgrav 
185480628bacSDag-Erling Smørgrav 	if (!use_privsep)
1855a04a10f8SKris Kennaway 		pty_setowner(s->pw, s->tty);
1856af12a3e7SDag-Erling Smørgrav 
1857af12a3e7SDag-Erling Smørgrav 	/* Set window size from the packet. */
1858a04a10f8SKris Kennaway 	pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
1859a04a10f8SKris Kennaway 
1860af12a3e7SDag-Erling Smørgrav 	packet_check_eom();
1861a04a10f8SKris Kennaway 	session_proctitle(s);
1862a04a10f8SKris Kennaway 	return 1;
1863a04a10f8SKris Kennaway }
1864a04a10f8SKris Kennaway 
1865af12a3e7SDag-Erling Smørgrav static int
1866a04a10f8SKris Kennaway session_subsystem_req(Session *s)
1867a04a10f8SKris Kennaway {
1868af12a3e7SDag-Erling Smørgrav 	struct stat st;
1869ca3176e7SBrian Feldman 	u_int len;
1870a04a10f8SKris Kennaway 	int success = 0;
1871af12a3e7SDag-Erling Smørgrav 	char *cmd, *subsys = packet_get_string(&len);
1872d4ecd108SDag-Erling Smørgrav 	u_int i;
1873a04a10f8SKris Kennaway 
1874af12a3e7SDag-Erling Smørgrav 	packet_check_eom();
1875cf2b5f3bSDag-Erling Smørgrav 	logit("subsystem request for %.100s", subsys);
1876a04a10f8SKris Kennaway 
1877c2d3a559SKris Kennaway 	for (i = 0; i < options.num_subsystems; i++) {
1878c2d3a559SKris Kennaway 		if (strcmp(subsys, options.subsystem_name[i]) == 0) {
1879af12a3e7SDag-Erling Smørgrav 			cmd = options.subsystem_command[i];
1880af12a3e7SDag-Erling Smørgrav 			if (stat(cmd, &st) < 0) {
1881af12a3e7SDag-Erling Smørgrav 				error("subsystem: cannot stat %s: %s", cmd,
1882af12a3e7SDag-Erling Smørgrav 				    strerror(errno));
1883af12a3e7SDag-Erling Smørgrav 				break;
1884af12a3e7SDag-Erling Smørgrav 			}
1885af12a3e7SDag-Erling Smørgrav 			debug("subsystem: exec() %s", cmd);
1886ca3176e7SBrian Feldman 			s->is_subsystem = 1;
1887af12a3e7SDag-Erling Smørgrav 			do_exec(s, cmd);
1888c2d3a559SKris Kennaway 			success = 1;
1889af12a3e7SDag-Erling Smørgrav 			break;
1890c2d3a559SKris Kennaway 		}
1891c2d3a559SKris Kennaway 	}
1892c2d3a559SKris Kennaway 
1893c2d3a559SKris Kennaway 	if (!success)
1894cf2b5f3bSDag-Erling Smørgrav 		logit("subsystem request for %.100s failed, subsystem not found",
1895af12a3e7SDag-Erling Smørgrav 		    subsys);
1896c2d3a559SKris Kennaway 
1897a04a10f8SKris Kennaway 	xfree(subsys);
1898a04a10f8SKris Kennaway 	return success;
1899a04a10f8SKris Kennaway }
1900a04a10f8SKris Kennaway 
1901af12a3e7SDag-Erling Smørgrav static int
1902a04a10f8SKris Kennaway session_x11_req(Session *s)
1903a04a10f8SKris Kennaway {
1904af12a3e7SDag-Erling Smørgrav 	int success;
1905a04a10f8SKris Kennaway 
1906d4ecd108SDag-Erling Smørgrav 	if (s->auth_proto != NULL || s->auth_data != NULL) {
1907d4ecd108SDag-Erling Smørgrav 		error("session_x11_req: session %d: "
1908d4ecd108SDag-Erling Smørgrav 		    "x11 fowarding already active", s->self);
1909d4ecd108SDag-Erling Smørgrav 		return 0;
1910d4ecd108SDag-Erling Smørgrav 	}
1911a04a10f8SKris Kennaway 	s->single_connection = packet_get_char();
1912a04a10f8SKris Kennaway 	s->auth_proto = packet_get_string(NULL);
1913a04a10f8SKris Kennaway 	s->auth_data = packet_get_string(NULL);
1914a04a10f8SKris Kennaway 	s->screen = packet_get_int();
1915af12a3e7SDag-Erling Smørgrav 	packet_check_eom();
1916a04a10f8SKris Kennaway 
1917af12a3e7SDag-Erling Smørgrav 	success = session_setup_x11fwd(s);
1918af12a3e7SDag-Erling Smørgrav 	if (!success) {
1919a04a10f8SKris Kennaway 		xfree(s->auth_proto);
1920a04a10f8SKris Kennaway 		xfree(s->auth_data);
1921af12a3e7SDag-Erling Smørgrav 		s->auth_proto = NULL;
1922af12a3e7SDag-Erling Smørgrav 		s->auth_data = NULL;
1923a04a10f8SKris Kennaway 	}
1924af12a3e7SDag-Erling Smørgrav 	return success;
1925a04a10f8SKris Kennaway }
1926a04a10f8SKris Kennaway 
1927af12a3e7SDag-Erling Smørgrav static int
1928c2d3a559SKris Kennaway session_shell_req(Session *s)
1929c2d3a559SKris Kennaway {
1930af12a3e7SDag-Erling Smørgrav 	packet_check_eom();
1931af12a3e7SDag-Erling Smørgrav 	do_exec(s, NULL);
1932c2d3a559SKris Kennaway 	return 1;
1933c2d3a559SKris Kennaway }
1934c2d3a559SKris Kennaway 
1935af12a3e7SDag-Erling Smørgrav static int
1936c2d3a559SKris Kennaway session_exec_req(Session *s)
1937c2d3a559SKris Kennaway {
1938ca3176e7SBrian Feldman 	u_int len;
1939c2d3a559SKris Kennaway 	char *command = packet_get_string(&len);
1940af12a3e7SDag-Erling Smørgrav 	packet_check_eom();
1941af12a3e7SDag-Erling Smørgrav 	do_exec(s, command);
1942c2d3a559SKris Kennaway 	xfree(command);
1943c2d3a559SKris Kennaway 	return 1;
1944c2d3a559SKris Kennaway }
1945c2d3a559SKris Kennaway 
1946af12a3e7SDag-Erling Smørgrav static int
1947cf2b5f3bSDag-Erling Smørgrav session_break_req(Session *s)
1948cf2b5f3bSDag-Erling Smørgrav {
1949cf2b5f3bSDag-Erling Smørgrav 
195021e764dfSDag-Erling Smørgrav 	packet_get_int();	/* ignored */
1951cf2b5f3bSDag-Erling Smørgrav 	packet_check_eom();
1952cf2b5f3bSDag-Erling Smørgrav 
1953cf2b5f3bSDag-Erling Smørgrav 	if (s->ttyfd == -1 ||
1954cf2b5f3bSDag-Erling Smørgrav 	    tcsendbreak(s->ttyfd, 0) < 0)
1955cf2b5f3bSDag-Erling Smørgrav 		return 0;
1956cf2b5f3bSDag-Erling Smørgrav 	return 1;
1957cf2b5f3bSDag-Erling Smørgrav }
1958cf2b5f3bSDag-Erling Smørgrav 
1959cf2b5f3bSDag-Erling Smørgrav static int
196021e764dfSDag-Erling Smørgrav session_env_req(Session *s)
196121e764dfSDag-Erling Smørgrav {
196221e764dfSDag-Erling Smørgrav 	char *name, *val;
196321e764dfSDag-Erling Smørgrav 	u_int name_len, val_len, i;
196421e764dfSDag-Erling Smørgrav 
196521e764dfSDag-Erling Smørgrav 	name = packet_get_string(&name_len);
196621e764dfSDag-Erling Smørgrav 	val = packet_get_string(&val_len);
196721e764dfSDag-Erling Smørgrav 	packet_check_eom();
196821e764dfSDag-Erling Smørgrav 
196921e764dfSDag-Erling Smørgrav 	/* Don't set too many environment variables */
197021e764dfSDag-Erling Smørgrav 	if (s->num_env > 128) {
197121e764dfSDag-Erling Smørgrav 		debug2("Ignoring env request %s: too many env vars", name);
197221e764dfSDag-Erling Smørgrav 		goto fail;
197321e764dfSDag-Erling Smørgrav 	}
197421e764dfSDag-Erling Smørgrav 
197521e764dfSDag-Erling Smørgrav 	for (i = 0; i < options.num_accept_env; i++) {
197621e764dfSDag-Erling Smørgrav 		if (match_pattern(name, options.accept_env[i])) {
197721e764dfSDag-Erling Smørgrav 			debug2("Setting env %d: %s=%s", s->num_env, name, val);
197821e764dfSDag-Erling Smørgrav 			s->env = xrealloc(s->env, sizeof(*s->env) *
197921e764dfSDag-Erling Smørgrav 			    (s->num_env + 1));
198021e764dfSDag-Erling Smørgrav 			s->env[s->num_env].name = name;
198121e764dfSDag-Erling Smørgrav 			s->env[s->num_env].val = val;
198221e764dfSDag-Erling Smørgrav 			s->num_env++;
198321e764dfSDag-Erling Smørgrav 			return (1);
198421e764dfSDag-Erling Smørgrav 		}
198521e764dfSDag-Erling Smørgrav 	}
198621e764dfSDag-Erling Smørgrav 	debug2("Ignoring env request %s: disallowed name", name);
198721e764dfSDag-Erling Smørgrav 
198821e764dfSDag-Erling Smørgrav  fail:
198921e764dfSDag-Erling Smørgrav 	xfree(name);
199021e764dfSDag-Erling Smørgrav 	xfree(val);
199121e764dfSDag-Erling Smørgrav 	return (0);
199221e764dfSDag-Erling Smørgrav }
199321e764dfSDag-Erling Smørgrav 
199421e764dfSDag-Erling Smørgrav static int
1995ca3176e7SBrian Feldman session_auth_agent_req(Session *s)
1996ca3176e7SBrian Feldman {
1997ca3176e7SBrian Feldman 	static int called = 0;
1998af12a3e7SDag-Erling Smørgrav 	packet_check_eom();
1999ca3176e7SBrian Feldman 	if (no_agent_forwarding_flag) {
2000ca3176e7SBrian Feldman 		debug("session_auth_agent_req: no_agent_forwarding_flag");
2001ca3176e7SBrian Feldman 		return 0;
2002ca3176e7SBrian Feldman 	}
2003ca3176e7SBrian Feldman 	if (called) {
2004ca3176e7SBrian Feldman 		return 0;
2005ca3176e7SBrian Feldman 	} else {
2006ca3176e7SBrian Feldman 		called = 1;
2007ca3176e7SBrian Feldman 		return auth_input_request_forwarding(s->pw);
2008ca3176e7SBrian Feldman 	}
2009ca3176e7SBrian Feldman }
2010ca3176e7SBrian Feldman 
2011af12a3e7SDag-Erling Smørgrav int
2012af12a3e7SDag-Erling Smørgrav session_input_channel_req(Channel *c, const char *rtype)
2013a04a10f8SKris Kennaway {
2014a04a10f8SKris Kennaway 	int success = 0;
2015a04a10f8SKris Kennaway 	Session *s;
2016a04a10f8SKris Kennaway 
2017af12a3e7SDag-Erling Smørgrav 	if ((s = session_by_channel(c->self)) == NULL) {
2018cf2b5f3bSDag-Erling Smørgrav 		logit("session_input_channel_req: no session %d req %.100s",
2019af12a3e7SDag-Erling Smørgrav 		    c->self, rtype);
2020af12a3e7SDag-Erling Smørgrav 		return 0;
2021af12a3e7SDag-Erling Smørgrav 	}
2022af12a3e7SDag-Erling Smørgrav 	debug("session_input_channel_req: session %d req %s", s->self, rtype);
2023a04a10f8SKris Kennaway 
2024a04a10f8SKris Kennaway 	/*
2025ca3176e7SBrian Feldman 	 * a session is in LARVAL state until a shell, a command
2026ca3176e7SBrian Feldman 	 * or a subsystem is executed
2027a04a10f8SKris Kennaway 	 */
2028a04a10f8SKris Kennaway 	if (c->type == SSH_CHANNEL_LARVAL) {
2029a04a10f8SKris Kennaway 		if (strcmp(rtype, "shell") == 0) {
2030c2d3a559SKris Kennaway 			success = session_shell_req(s);
2031a04a10f8SKris Kennaway 		} else if (strcmp(rtype, "exec") == 0) {
2032c2d3a559SKris Kennaway 			success = session_exec_req(s);
2033a04a10f8SKris Kennaway 		} else if (strcmp(rtype, "pty-req") == 0) {
2034a04a10f8SKris Kennaway 			success =  session_pty_req(s);
2035a04a10f8SKris Kennaway 		} else if (strcmp(rtype, "x11-req") == 0) {
2036a04a10f8SKris Kennaway 			success = session_x11_req(s);
2037ca3176e7SBrian Feldman 		} else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) {
2038ca3176e7SBrian Feldman 			success = session_auth_agent_req(s);
2039a04a10f8SKris Kennaway 		} else if (strcmp(rtype, "subsystem") == 0) {
2040a04a10f8SKris Kennaway 			success = session_subsystem_req(s);
204121e764dfSDag-Erling Smørgrav 		} else if (strcmp(rtype, "env") == 0) {
204221e764dfSDag-Erling Smørgrav 			success = session_env_req(s);
2043a04a10f8SKris Kennaway 		}
2044a04a10f8SKris Kennaway 	}
2045a04a10f8SKris Kennaway 	if (strcmp(rtype, "window-change") == 0) {
2046a04a10f8SKris Kennaway 		success = session_window_change_req(s);
204721e764dfSDag-Erling Smørgrav 	} else if (strcmp(rtype, "break") == 0) {
204821e764dfSDag-Erling Smørgrav 		success = session_break_req(s);
2049a04a10f8SKris Kennaway 	}
205021e764dfSDag-Erling Smørgrav 
2051af12a3e7SDag-Erling Smørgrav 	return success;
2052a04a10f8SKris Kennaway }
2053a04a10f8SKris Kennaway 
2054a04a10f8SKris Kennaway void
2055a04a10f8SKris Kennaway session_set_fds(Session *s, int fdin, int fdout, int fderr)
2056a04a10f8SKris Kennaway {
2057a04a10f8SKris Kennaway 	if (!compat20)
2058a04a10f8SKris Kennaway 		fatal("session_set_fds: called for proto != 2.0");
2059a04a10f8SKris Kennaway 	/*
2060a04a10f8SKris Kennaway 	 * now that have a child and a pipe to the child,
2061a04a10f8SKris Kennaway 	 * we can activate our channel and register the fd's
2062a04a10f8SKris Kennaway 	 */
2063a04a10f8SKris Kennaway 	if (s->chanid == -1)
2064a04a10f8SKris Kennaway 		fatal("no channel for session %d", s->self);
2065a04a10f8SKris Kennaway 	channel_set_fds(s->chanid,
2066a04a10f8SKris Kennaway 	    fdout, fdin, fderr,
206709958426SBrian Feldman 	    fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
2068af12a3e7SDag-Erling Smørgrav 	    1,
2069af12a3e7SDag-Erling Smørgrav 	    CHAN_SES_WINDOW_DEFAULT);
2070a04a10f8SKris Kennaway }
2071a04a10f8SKris Kennaway 
2072af12a3e7SDag-Erling Smørgrav /*
2073af12a3e7SDag-Erling Smørgrav  * Function to perform pty cleanup. Also called if we get aborted abnormally
2074af12a3e7SDag-Erling Smørgrav  * (e.g., due to a dropped connection).
2075af12a3e7SDag-Erling Smørgrav  */
207680628bacSDag-Erling Smørgrav void
20771ec0d754SDag-Erling Smørgrav session_pty_cleanup2(Session *s)
2078a04a10f8SKris Kennaway {
2079af12a3e7SDag-Erling Smørgrav 	if (s == NULL) {
2080af12a3e7SDag-Erling Smørgrav 		error("session_pty_cleanup: no session");
2081af12a3e7SDag-Erling Smørgrav 		return;
2082af12a3e7SDag-Erling Smørgrav 	}
2083af12a3e7SDag-Erling Smørgrav 	if (s->ttyfd == -1)
2084a04a10f8SKris Kennaway 		return;
2085a04a10f8SKris Kennaway 
2086ca3176e7SBrian Feldman 	debug("session_pty_cleanup: session %d release %s", s->self, s->tty);
2087a04a10f8SKris Kennaway 
2088a04a10f8SKris Kennaway 	/* Record that the user has logged out. */
2089af12a3e7SDag-Erling Smørgrav 	if (s->pid != 0)
2090989dd127SDag-Erling Smørgrav 		record_logout(s->pid, s->tty, s->pw->pw_name);
2091a04a10f8SKris Kennaway 
2092a04a10f8SKris Kennaway 	/* Release the pseudo-tty. */
209380628bacSDag-Erling Smørgrav 	if (getuid() == 0)
2094a04a10f8SKris Kennaway 		pty_release(s->tty);
2095a04a10f8SKris Kennaway 
2096a04a10f8SKris Kennaway 	/*
2097a04a10f8SKris Kennaway 	 * Close the server side of the socket pairs.  We must do this after
2098a04a10f8SKris Kennaway 	 * the pty cleanup, so that another process doesn't get this pty
2099a04a10f8SKris Kennaway 	 * while we're still cleaning up.
2100a04a10f8SKris Kennaway 	 */
2101a04a10f8SKris Kennaway 	if (close(s->ptymaster) < 0)
210280628bacSDag-Erling Smørgrav 		error("close(s->ptymaster/%d): %s", s->ptymaster, strerror(errno));
2103af12a3e7SDag-Erling Smørgrav 
2104af12a3e7SDag-Erling Smørgrav 	/* unlink pty from session */
2105af12a3e7SDag-Erling Smørgrav 	s->ttyfd = -1;
2106a04a10f8SKris Kennaway }
2107a04a10f8SKris Kennaway 
210880628bacSDag-Erling Smørgrav void
21091ec0d754SDag-Erling Smørgrav session_pty_cleanup(Session *s)
211080628bacSDag-Erling Smørgrav {
21111ec0d754SDag-Erling Smørgrav 	PRIVSEP(session_pty_cleanup2(s));
211280628bacSDag-Erling Smørgrav }
211380628bacSDag-Erling Smørgrav 
2114f388f5efSDag-Erling Smørgrav static char *
2115f388f5efSDag-Erling Smørgrav sig2name(int sig)
2116f388f5efSDag-Erling Smørgrav {
2117f388f5efSDag-Erling Smørgrav #define SSH_SIG(x) if (sig == SIG ## x) return #x
2118f388f5efSDag-Erling Smørgrav 	SSH_SIG(ABRT);
2119f388f5efSDag-Erling Smørgrav 	SSH_SIG(ALRM);
2120f388f5efSDag-Erling Smørgrav 	SSH_SIG(FPE);
2121f388f5efSDag-Erling Smørgrav 	SSH_SIG(HUP);
2122f388f5efSDag-Erling Smørgrav 	SSH_SIG(ILL);
2123f388f5efSDag-Erling Smørgrav 	SSH_SIG(INT);
2124f388f5efSDag-Erling Smørgrav 	SSH_SIG(KILL);
2125f388f5efSDag-Erling Smørgrav 	SSH_SIG(PIPE);
2126f388f5efSDag-Erling Smørgrav 	SSH_SIG(QUIT);
2127f388f5efSDag-Erling Smørgrav 	SSH_SIG(SEGV);
2128f388f5efSDag-Erling Smørgrav 	SSH_SIG(TERM);
2129f388f5efSDag-Erling Smørgrav 	SSH_SIG(USR1);
2130f388f5efSDag-Erling Smørgrav 	SSH_SIG(USR2);
2131f388f5efSDag-Erling Smørgrav #undef	SSH_SIG
2132f388f5efSDag-Erling Smørgrav 	return "SIG@openssh.com";
2133f388f5efSDag-Erling Smørgrav }
2134f388f5efSDag-Erling Smørgrav 
2135af12a3e7SDag-Erling Smørgrav static void
2136d4ecd108SDag-Erling Smørgrav session_close_x11(int id)
2137d4ecd108SDag-Erling Smørgrav {
2138d4ecd108SDag-Erling Smørgrav 	Channel *c;
2139d4ecd108SDag-Erling Smørgrav 
2140d4ecd108SDag-Erling Smørgrav 	if ((c = channel_lookup(id)) == NULL) {
2141d4ecd108SDag-Erling Smørgrav 		debug("session_close_x11: x11 channel %d missing", id);
2142d4ecd108SDag-Erling Smørgrav 	} else {
2143d4ecd108SDag-Erling Smørgrav 		/* Detach X11 listener */
2144d4ecd108SDag-Erling Smørgrav 		debug("session_close_x11: detach x11 channel %d", id);
2145d4ecd108SDag-Erling Smørgrav 		channel_cancel_cleanup(id);
2146d4ecd108SDag-Erling Smørgrav 		if (c->ostate != CHAN_OUTPUT_CLOSED)
2147d4ecd108SDag-Erling Smørgrav 			chan_mark_dead(c);
2148d4ecd108SDag-Erling Smørgrav 	}
2149d4ecd108SDag-Erling Smørgrav }
2150d4ecd108SDag-Erling Smørgrav 
2151d4ecd108SDag-Erling Smørgrav static void
2152d4ecd108SDag-Erling Smørgrav session_close_single_x11(int id, void *arg)
2153d4ecd108SDag-Erling Smørgrav {
2154d4ecd108SDag-Erling Smørgrav 	Session *s;
2155d4ecd108SDag-Erling Smørgrav 	u_int i;
2156d4ecd108SDag-Erling Smørgrav 
2157d4ecd108SDag-Erling Smørgrav 	debug3("session_close_single_x11: channel %d", id);
2158d4ecd108SDag-Erling Smørgrav 	channel_cancel_cleanup(id);
2159d4ecd108SDag-Erling Smørgrav 	if ((s  = session_by_x11_channel(id)) == NULL)
2160d4ecd108SDag-Erling Smørgrav 		fatal("session_close_single_x11: no x11 channel %d", id);
2161d4ecd108SDag-Erling Smørgrav 	for (i = 0; s->x11_chanids[i] != -1; i++) {
2162d4ecd108SDag-Erling Smørgrav 		debug("session_close_single_x11: session %d: "
2163d4ecd108SDag-Erling Smørgrav 		    "closing channel %d", s->self, s->x11_chanids[i]);
2164d4ecd108SDag-Erling Smørgrav 		/*
2165d4ecd108SDag-Erling Smørgrav 		 * The channel "id" is already closing, but make sure we
2166d4ecd108SDag-Erling Smørgrav 		 * close all of its siblings.
2167d4ecd108SDag-Erling Smørgrav 		 */
2168d4ecd108SDag-Erling Smørgrav 		if (s->x11_chanids[i] != id)
2169d4ecd108SDag-Erling Smørgrav 			session_close_x11(s->x11_chanids[i]);
2170d4ecd108SDag-Erling Smørgrav 	}
2171d4ecd108SDag-Erling Smørgrav 	xfree(s->x11_chanids);
2172d4ecd108SDag-Erling Smørgrav 	s->x11_chanids = NULL;
2173d4ecd108SDag-Erling Smørgrav 	if (s->display) {
2174d4ecd108SDag-Erling Smørgrav 		xfree(s->display);
2175d4ecd108SDag-Erling Smørgrav 		s->display = NULL;
2176d4ecd108SDag-Erling Smørgrav 	}
2177d4ecd108SDag-Erling Smørgrav 	if (s->auth_proto) {
2178d4ecd108SDag-Erling Smørgrav 		xfree(s->auth_proto);
2179d4ecd108SDag-Erling Smørgrav 		s->auth_proto = NULL;
2180d4ecd108SDag-Erling Smørgrav 	}
2181d4ecd108SDag-Erling Smørgrav 	if (s->auth_data) {
2182d4ecd108SDag-Erling Smørgrav 		xfree(s->auth_data);
2183d4ecd108SDag-Erling Smørgrav 		s->auth_data = NULL;
2184d4ecd108SDag-Erling Smørgrav 	}
2185d4ecd108SDag-Erling Smørgrav 	if (s->auth_display) {
2186d4ecd108SDag-Erling Smørgrav 		xfree(s->auth_display);
2187d4ecd108SDag-Erling Smørgrav 		s->auth_display = NULL;
2188d4ecd108SDag-Erling Smørgrav 	}
2189d4ecd108SDag-Erling Smørgrav }
2190d4ecd108SDag-Erling Smørgrav 
2191d4ecd108SDag-Erling Smørgrav static void
2192a04a10f8SKris Kennaway session_exit_message(Session *s, int status)
2193a04a10f8SKris Kennaway {
2194a04a10f8SKris Kennaway 	Channel *c;
2195d4ecd108SDag-Erling Smørgrav 	u_int i;
2196af12a3e7SDag-Erling Smørgrav 
2197af12a3e7SDag-Erling Smørgrav 	if ((c = channel_lookup(s->chanid)) == NULL)
2198af12a3e7SDag-Erling Smørgrav 		fatal("session_exit_message: session %d: no channel %d",
2199a04a10f8SKris Kennaway 		    s->self, s->chanid);
220080628bacSDag-Erling Smørgrav 	debug("session_exit_message: session %d channel %d pid %ld",
220180628bacSDag-Erling Smørgrav 	    s->self, s->chanid, (long)s->pid);
2202a04a10f8SKris Kennaway 
2203a04a10f8SKris Kennaway 	if (WIFEXITED(status)) {
2204af12a3e7SDag-Erling Smørgrav 		channel_request_start(s->chanid, "exit-status", 0);
2205a04a10f8SKris Kennaway 		packet_put_int(WEXITSTATUS(status));
2206a04a10f8SKris Kennaway 		packet_send();
2207a04a10f8SKris Kennaway 	} else if (WIFSIGNALED(status)) {
2208af12a3e7SDag-Erling Smørgrav 		channel_request_start(s->chanid, "exit-signal", 0);
2209f388f5efSDag-Erling Smørgrav 		packet_put_cstring(sig2name(WTERMSIG(status)));
2210989dd127SDag-Erling Smørgrav #ifdef WCOREDUMP
2211a04a10f8SKris Kennaway 		packet_put_char(WCOREDUMP(status));
2212989dd127SDag-Erling Smørgrav #else /* WCOREDUMP */
2213989dd127SDag-Erling Smørgrav 		packet_put_char(0);
2214989dd127SDag-Erling Smørgrav #endif /* WCOREDUMP */
2215a04a10f8SKris Kennaway 		packet_put_cstring("");
2216a04a10f8SKris Kennaway 		packet_put_cstring("");
2217a04a10f8SKris Kennaway 		packet_send();
2218a04a10f8SKris Kennaway 	} else {
2219a04a10f8SKris Kennaway 		/* Some weird exit cause.  Just exit. */
2220a04a10f8SKris Kennaway 		packet_disconnect("wait returned status %04x.", status);
2221a04a10f8SKris Kennaway 	}
2222a04a10f8SKris Kennaway 
2223a04a10f8SKris Kennaway 	/* disconnect channel */
2224a04a10f8SKris Kennaway 	debug("session_exit_message: release channel %d", s->chanid);
2225a04a10f8SKris Kennaway 	channel_cancel_cleanup(s->chanid);
2226a04a10f8SKris Kennaway 	/*
2227a04a10f8SKris Kennaway 	 * emulate a write failure with 'chan_write_failed', nobody will be
2228a04a10f8SKris Kennaway 	 * interested in data we write.
2229a04a10f8SKris Kennaway 	 * Note that we must not call 'chan_read_failed', since there could
2230a04a10f8SKris Kennaway 	 * be some more data waiting in the pipe.
2231a04a10f8SKris Kennaway 	 */
2232a04a10f8SKris Kennaway 	if (c->ostate != CHAN_OUTPUT_CLOSED)
2233a04a10f8SKris Kennaway 		chan_write_failed(c);
2234a04a10f8SKris Kennaway 	s->chanid = -1;
2235d4ecd108SDag-Erling Smørgrav 
2236d4ecd108SDag-Erling Smørgrav 	/* Close any X11 listeners associated with this session */
2237d4ecd108SDag-Erling Smørgrav 	if (s->x11_chanids != NULL) {
2238d4ecd108SDag-Erling Smørgrav 		for (i = 0; s->x11_chanids[i] != -1; i++) {
2239d4ecd108SDag-Erling Smørgrav 			session_close_x11(s->x11_chanids[i]);
2240d4ecd108SDag-Erling Smørgrav 			s->x11_chanids[i] = -1;
2241d4ecd108SDag-Erling Smørgrav 		}
2242d4ecd108SDag-Erling Smørgrav 	}
2243a04a10f8SKris Kennaway }
2244a04a10f8SKris Kennaway 
224580628bacSDag-Erling Smørgrav void
2246af12a3e7SDag-Erling Smørgrav session_close(Session *s)
2247a04a10f8SKris Kennaway {
2248d4ecd108SDag-Erling Smørgrav 	u_int i;
224921e764dfSDag-Erling Smørgrav 
225080628bacSDag-Erling Smørgrav 	debug("session_close: session %d pid %ld", s->self, (long)s->pid);
22511ec0d754SDag-Erling Smørgrav 	if (s->ttyfd != -1)
2252af12a3e7SDag-Erling Smørgrav 		session_pty_cleanup(s);
2253a04a10f8SKris Kennaway 	if (s->term)
2254a04a10f8SKris Kennaway 		xfree(s->term);
2255a04a10f8SKris Kennaway 	if (s->display)
2256a04a10f8SKris Kennaway 		xfree(s->display);
2257d4ecd108SDag-Erling Smørgrav 	if (s->x11_chanids)
2258d4ecd108SDag-Erling Smørgrav 		xfree(s->x11_chanids);
2259af12a3e7SDag-Erling Smørgrav 	if (s->auth_display)
2260af12a3e7SDag-Erling Smørgrav 		xfree(s->auth_display);
2261a04a10f8SKris Kennaway 	if (s->auth_data)
2262a04a10f8SKris Kennaway 		xfree(s->auth_data);
2263a04a10f8SKris Kennaway 	if (s->auth_proto)
2264a04a10f8SKris Kennaway 		xfree(s->auth_proto);
2265a04a10f8SKris Kennaway 	s->used = 0;
226621e764dfSDag-Erling Smørgrav 	for (i = 0; i < s->num_env; i++) {
226721e764dfSDag-Erling Smørgrav 		xfree(s->env[i].name);
226821e764dfSDag-Erling Smørgrav 		xfree(s->env[i].val);
226921e764dfSDag-Erling Smørgrav 	}
227021e764dfSDag-Erling Smørgrav 	if (s->env != NULL)
227121e764dfSDag-Erling Smørgrav 		xfree(s->env);
2272a04a10f8SKris Kennaway 	session_proctitle(s);
2273a04a10f8SKris Kennaway }
2274a04a10f8SKris Kennaway 
2275a04a10f8SKris Kennaway void
2276a04a10f8SKris Kennaway session_close_by_pid(pid_t pid, int status)
2277a04a10f8SKris Kennaway {
2278a04a10f8SKris Kennaway 	Session *s = session_by_pid(pid);
2279a04a10f8SKris Kennaway 	if (s == NULL) {
228080628bacSDag-Erling Smørgrav 		debug("session_close_by_pid: no session for pid %ld",
228180628bacSDag-Erling Smørgrav 		    (long)pid);
2282a04a10f8SKris Kennaway 		return;
2283a04a10f8SKris Kennaway 	}
2284a04a10f8SKris Kennaway 	if (s->chanid != -1)
2285a04a10f8SKris Kennaway 		session_exit_message(s, status);
2286a04a10f8SKris Kennaway 	session_close(s);
2287a04a10f8SKris Kennaway }
2288a04a10f8SKris Kennaway 
2289a04a10f8SKris Kennaway /*
2290a04a10f8SKris Kennaway  * this is called when a channel dies before
2291a04a10f8SKris Kennaway  * the session 'child' itself dies
2292a04a10f8SKris Kennaway  */
2293a04a10f8SKris Kennaway void
2294a04a10f8SKris Kennaway session_close_by_channel(int id, void *arg)
2295a04a10f8SKris Kennaway {
2296a04a10f8SKris Kennaway 	Session *s = session_by_channel(id);
2297d4ecd108SDag-Erling Smørgrav 
2298a04a10f8SKris Kennaway 	if (s == NULL) {
2299af12a3e7SDag-Erling Smørgrav 		debug("session_close_by_channel: no session for id %d", id);
2300a04a10f8SKris Kennaway 		return;
2301a04a10f8SKris Kennaway 	}
230280628bacSDag-Erling Smørgrav 	debug("session_close_by_channel: channel %d child %ld",
230380628bacSDag-Erling Smørgrav 	    id, (long)s->pid);
2304af12a3e7SDag-Erling Smørgrav 	if (s->pid != 0) {
2305af12a3e7SDag-Erling Smørgrav 		debug("session_close_by_channel: channel %d: has child", id);
2306af12a3e7SDag-Erling Smørgrav 		/*
2307af12a3e7SDag-Erling Smørgrav 		 * delay detach of session, but release pty, since
2308af12a3e7SDag-Erling Smørgrav 		 * the fd's to the child are already closed
2309af12a3e7SDag-Erling Smørgrav 		 */
23101ec0d754SDag-Erling Smørgrav 		if (s->ttyfd != -1)
2311af12a3e7SDag-Erling Smørgrav 			session_pty_cleanup(s);
2312af12a3e7SDag-Erling Smørgrav 		return;
2313af12a3e7SDag-Erling Smørgrav 	}
2314af12a3e7SDag-Erling Smørgrav 	/* detach by removing callback */
2315a04a10f8SKris Kennaway 	channel_cancel_cleanup(s->chanid);
2316a04a10f8SKris Kennaway 	s->chanid = -1;
2317a04a10f8SKris Kennaway 	session_close(s);
2318af12a3e7SDag-Erling Smørgrav }
2319af12a3e7SDag-Erling Smørgrav 
2320af12a3e7SDag-Erling Smørgrav void
232180628bacSDag-Erling Smørgrav session_destroy_all(void (*closefunc)(Session *))
2322af12a3e7SDag-Erling Smørgrav {
2323af12a3e7SDag-Erling Smørgrav 	int i;
2324af12a3e7SDag-Erling Smørgrav 	for (i = 0; i < MAX_SESSIONS; i++) {
2325af12a3e7SDag-Erling Smørgrav 		Session *s = &sessions[i];
232680628bacSDag-Erling Smørgrav 		if (s->used) {
232780628bacSDag-Erling Smørgrav 			if (closefunc != NULL)
232880628bacSDag-Erling Smørgrav 				closefunc(s);
232980628bacSDag-Erling Smørgrav 			else
2330af12a3e7SDag-Erling Smørgrav 				session_close(s);
2331a04a10f8SKris Kennaway 		}
2332a04a10f8SKris Kennaway 	}
233380628bacSDag-Erling Smørgrav }
2334a04a10f8SKris Kennaway 
2335af12a3e7SDag-Erling Smørgrav static char *
2336a04a10f8SKris Kennaway session_tty_list(void)
2337a04a10f8SKris Kennaway {
2338a04a10f8SKris Kennaway 	static char buf[1024];
2339a04a10f8SKris Kennaway 	int i;
2340e73e9afaSDag-Erling Smørgrav 	char *cp;
2341e73e9afaSDag-Erling Smørgrav 
2342a04a10f8SKris Kennaway 	buf[0] = '\0';
2343a04a10f8SKris Kennaway 	for (i = 0; i < MAX_SESSIONS; i++) {
2344a04a10f8SKris Kennaway 		Session *s = &sessions[i];
2345a04a10f8SKris Kennaway 		if (s->used && s->ttyfd != -1) {
2346e73e9afaSDag-Erling Smørgrav 
2347e73e9afaSDag-Erling Smørgrav 			if (strncmp(s->tty, "/dev/", 5) != 0) {
2348e73e9afaSDag-Erling Smørgrav 				cp = strrchr(s->tty, '/');
2349e73e9afaSDag-Erling Smørgrav 				cp = (cp == NULL) ? s->tty : cp + 1;
2350e73e9afaSDag-Erling Smørgrav 			} else
2351e73e9afaSDag-Erling Smørgrav 				cp = s->tty + 5;
2352e73e9afaSDag-Erling Smørgrav 
2353a04a10f8SKris Kennaway 			if (buf[0] != '\0')
2354a04a10f8SKris Kennaway 				strlcat(buf, ",", sizeof buf);
2355e73e9afaSDag-Erling Smørgrav 			strlcat(buf, cp, sizeof buf);
2356a04a10f8SKris Kennaway 		}
2357a04a10f8SKris Kennaway 	}
2358a04a10f8SKris Kennaway 	if (buf[0] == '\0')
2359a04a10f8SKris Kennaway 		strlcpy(buf, "notty", sizeof buf);
2360a04a10f8SKris Kennaway 	return buf;
2361a04a10f8SKris Kennaway }
2362a04a10f8SKris Kennaway 
2363a04a10f8SKris Kennaway void
2364a04a10f8SKris Kennaway session_proctitle(Session *s)
2365a04a10f8SKris Kennaway {
2366a04a10f8SKris Kennaway 	if (s->pw == NULL)
2367a04a10f8SKris Kennaway 		error("no user for session %d", s->self);
2368a04a10f8SKris Kennaway 	else
2369a04a10f8SKris Kennaway 		setproctitle("%s@%s", s->pw->pw_name, session_tty_list());
2370a04a10f8SKris Kennaway }
2371a04a10f8SKris Kennaway 
2372af12a3e7SDag-Erling Smørgrav int
2373af12a3e7SDag-Erling Smørgrav session_setup_x11fwd(Session *s)
2374af12a3e7SDag-Erling Smørgrav {
2375af12a3e7SDag-Erling Smørgrav 	struct stat st;
2376af12a3e7SDag-Erling Smørgrav 	char display[512], auth_display[512];
2377af12a3e7SDag-Erling Smørgrav 	char hostname[MAXHOSTNAMELEN];
2378d4ecd108SDag-Erling Smørgrav 	u_int i;
2379af12a3e7SDag-Erling Smørgrav 
2380af12a3e7SDag-Erling Smørgrav 	if (no_x11_forwarding_flag) {
2381af12a3e7SDag-Erling Smørgrav 		packet_send_debug("X11 forwarding disabled in user configuration file.");
2382af12a3e7SDag-Erling Smørgrav 		return 0;
2383af12a3e7SDag-Erling Smørgrav 	}
2384af12a3e7SDag-Erling Smørgrav 	if (!options.x11_forwarding) {
2385af12a3e7SDag-Erling Smørgrav 		debug("X11 forwarding disabled in server configuration file.");
2386af12a3e7SDag-Erling Smørgrav 		return 0;
2387af12a3e7SDag-Erling Smørgrav 	}
2388af12a3e7SDag-Erling Smørgrav 	if (!options.xauth_location ||
2389af12a3e7SDag-Erling Smørgrav 	    (stat(options.xauth_location, &st) == -1)) {
2390af12a3e7SDag-Erling Smørgrav 		packet_send_debug("No xauth program; cannot forward with spoofing.");
2391af12a3e7SDag-Erling Smørgrav 		return 0;
2392af12a3e7SDag-Erling Smørgrav 	}
2393af12a3e7SDag-Erling Smørgrav 	if (options.use_login) {
2394af12a3e7SDag-Erling Smørgrav 		packet_send_debug("X11 forwarding disabled; "
2395af12a3e7SDag-Erling Smørgrav 		    "not compatible with UseLogin=yes.");
2396af12a3e7SDag-Erling Smørgrav 		return 0;
2397af12a3e7SDag-Erling Smørgrav 	}
2398af12a3e7SDag-Erling Smørgrav 	if (s->display != NULL) {
2399af12a3e7SDag-Erling Smørgrav 		debug("X11 display already set.");
2400af12a3e7SDag-Erling Smørgrav 		return 0;
2401af12a3e7SDag-Erling Smørgrav 	}
2402a82e551fSDag-Erling Smørgrav 	if (x11_create_display_inet(options.x11_display_offset,
2403a82e551fSDag-Erling Smørgrav 	    options.x11_use_localhost, s->single_connection,
2404d4ecd108SDag-Erling Smørgrav 	    &s->display_number, &s->x11_chanids) == -1) {
2405af12a3e7SDag-Erling Smørgrav 		debug("x11_create_display_inet failed.");
2406af12a3e7SDag-Erling Smørgrav 		return 0;
2407af12a3e7SDag-Erling Smørgrav 	}
2408d4ecd108SDag-Erling Smørgrav 	for (i = 0; s->x11_chanids[i] != -1; i++) {
2409d4ecd108SDag-Erling Smørgrav 		channel_register_cleanup(s->x11_chanids[i],
2410d4ecd108SDag-Erling Smørgrav 		    session_close_single_x11);
2411d4ecd108SDag-Erling Smørgrav 	}
2412af12a3e7SDag-Erling Smørgrav 
2413af12a3e7SDag-Erling Smørgrav 	/* Set up a suitable value for the DISPLAY variable. */
2414af12a3e7SDag-Erling Smørgrav 	if (gethostname(hostname, sizeof(hostname)) < 0)
2415af12a3e7SDag-Erling Smørgrav 		fatal("gethostname: %.100s", strerror(errno));
2416af12a3e7SDag-Erling Smørgrav 	/*
2417af12a3e7SDag-Erling Smørgrav 	 * auth_display must be used as the displayname when the
2418af12a3e7SDag-Erling Smørgrav 	 * authorization entry is added with xauth(1).  This will be
2419af12a3e7SDag-Erling Smørgrav 	 * different than the DISPLAY string for localhost displays.
2420af12a3e7SDag-Erling Smørgrav 	 */
2421af12a3e7SDag-Erling Smørgrav 	if (options.x11_use_localhost) {
2422a82e551fSDag-Erling Smørgrav 		snprintf(display, sizeof display, "localhost:%u.%u",
2423af12a3e7SDag-Erling Smørgrav 		    s->display_number, s->screen);
2424a82e551fSDag-Erling Smørgrav 		snprintf(auth_display, sizeof auth_display, "unix:%u.%u",
2425af12a3e7SDag-Erling Smørgrav 		    s->display_number, s->screen);
2426af12a3e7SDag-Erling Smørgrav 		s->display = xstrdup(display);
2427af12a3e7SDag-Erling Smørgrav 		s->auth_display = xstrdup(auth_display);
2428af12a3e7SDag-Erling Smørgrav 	} else {
2429989dd127SDag-Erling Smørgrav #ifdef IPADDR_IN_DISPLAY
2430989dd127SDag-Erling Smørgrav 		struct hostent *he;
2431989dd127SDag-Erling Smørgrav 		struct in_addr my_addr;
2432989dd127SDag-Erling Smørgrav 
2433989dd127SDag-Erling Smørgrav 		he = gethostbyname(hostname);
2434989dd127SDag-Erling Smørgrav 		if (he == NULL) {
2435989dd127SDag-Erling Smørgrav 			error("Can't get IP address for X11 DISPLAY.");
2436989dd127SDag-Erling Smørgrav 			packet_send_debug("Can't get IP address for X11 DISPLAY.");
2437989dd127SDag-Erling Smørgrav 			return 0;
2438989dd127SDag-Erling Smørgrav 		}
2439989dd127SDag-Erling Smørgrav 		memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr));
2440a82e551fSDag-Erling Smørgrav 		snprintf(display, sizeof display, "%.50s:%u.%u", inet_ntoa(my_addr),
2441989dd127SDag-Erling Smørgrav 		    s->display_number, s->screen);
2442989dd127SDag-Erling Smørgrav #else
2443a82e551fSDag-Erling Smørgrav 		snprintf(display, sizeof display, "%.400s:%u.%u", hostname,
2444af12a3e7SDag-Erling Smørgrav 		    s->display_number, s->screen);
2445989dd127SDag-Erling Smørgrav #endif
2446af12a3e7SDag-Erling Smørgrav 		s->display = xstrdup(display);
2447af12a3e7SDag-Erling Smørgrav 		s->auth_display = xstrdup(display);
2448af12a3e7SDag-Erling Smørgrav 	}
2449af12a3e7SDag-Erling Smørgrav 
2450af12a3e7SDag-Erling Smørgrav 	return 1;
2451af12a3e7SDag-Erling Smørgrav }
2452af12a3e7SDag-Erling Smørgrav 
2453af12a3e7SDag-Erling Smørgrav static void
2454ca3176e7SBrian Feldman do_authenticated2(Authctxt *authctxt)
2455a04a10f8SKris Kennaway {
2456af12a3e7SDag-Erling Smørgrav 	server_loop2(authctxt);
24571ec0d754SDag-Erling Smørgrav }
24581ec0d754SDag-Erling Smørgrav 
24591ec0d754SDag-Erling Smørgrav void
24601ec0d754SDag-Erling Smørgrav do_cleanup(Authctxt *authctxt)
24611ec0d754SDag-Erling Smørgrav {
24621ec0d754SDag-Erling Smørgrav 	static int called = 0;
24631ec0d754SDag-Erling Smørgrav 
24641ec0d754SDag-Erling Smørgrav 	debug("do_cleanup");
24651ec0d754SDag-Erling Smørgrav 
24661ec0d754SDag-Erling Smørgrav 	/* no cleanup if we're in the child for login shell */
24671ec0d754SDag-Erling Smørgrav 	if (is_child)
24681ec0d754SDag-Erling Smørgrav 		return;
24691ec0d754SDag-Erling Smørgrav 
24701ec0d754SDag-Erling Smørgrav 	/* avoid double cleanup */
24711ec0d754SDag-Erling Smørgrav 	if (called)
24721ec0d754SDag-Erling Smørgrav 		return;
24731ec0d754SDag-Erling Smørgrav 	called = 1;
24741ec0d754SDag-Erling Smørgrav 
24751ec0d754SDag-Erling Smørgrav 	if (authctxt == NULL)
24761ec0d754SDag-Erling Smørgrav 		return;
24771ec0d754SDag-Erling Smørgrav #ifdef KRB5
24781ec0d754SDag-Erling Smørgrav 	if (options.kerberos_ticket_cleanup &&
24791ec0d754SDag-Erling Smørgrav 	    authctxt->krb5_ctx)
24801ec0d754SDag-Erling Smørgrav 		krb5_cleanup_proc(authctxt);
2481cf2b5f3bSDag-Erling Smørgrav #endif
24821ec0d754SDag-Erling Smørgrav 
24831ec0d754SDag-Erling Smørgrav #ifdef GSSAPI
24841ec0d754SDag-Erling Smørgrav 	if (compat20 && options.gss_cleanup_creds)
24851ec0d754SDag-Erling Smørgrav 		ssh_gssapi_cleanup_creds();
24861ec0d754SDag-Erling Smørgrav #endif
24871ec0d754SDag-Erling Smørgrav 
24881ec0d754SDag-Erling Smørgrav #ifdef USE_PAM
24891ec0d754SDag-Erling Smørgrav 	if (options.use_pam) {
24901ec0d754SDag-Erling Smørgrav 		sshpam_cleanup();
24911ec0d754SDag-Erling Smørgrav 		sshpam_thread_cleanup();
24921ec0d754SDag-Erling Smørgrav 	}
24931ec0d754SDag-Erling Smørgrav #endif
24941ec0d754SDag-Erling Smørgrav 
24951ec0d754SDag-Erling Smørgrav 	/* remove agent socket */
24961ec0d754SDag-Erling Smørgrav 	auth_sock_cleanup_proc(authctxt->pw);
24971ec0d754SDag-Erling Smørgrav 
24981ec0d754SDag-Erling Smørgrav 	/*
24991ec0d754SDag-Erling Smørgrav 	 * Cleanup ptys/utmp only if privsep is disabled,
25001ec0d754SDag-Erling Smørgrav 	 * or if running in monitor.
25011ec0d754SDag-Erling Smørgrav 	 */
25021ec0d754SDag-Erling Smørgrav 	if (!use_privsep || mm_is_monitor())
25031ec0d754SDag-Erling Smørgrav 		session_destroy_all(session_pty_cleanup2);
2504a04a10f8SKris Kennaway }
2505