xref: /freebsd/crypto/openssh/session.c (revision db1cb46ca2e70fbd8357ff6c8acc5f7f07b36b3f)
1a04a10f8SKris Kennaway /*
2a04a10f8SKris Kennaway  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
3a04a10f8SKris Kennaway  *                    All rights reserved
4a04a10f8SKris Kennaway  */
5a04a10f8SKris Kennaway /*
6a04a10f8SKris Kennaway  * SSH2 support by Markus Friedl.
7a04a10f8SKris Kennaway  * Copyright (c) 2000 Markus Friedl. All rights reserved.
8e8aafc91SKris Kennaway  *
9e8aafc91SKris Kennaway  * $FreeBSD$
10a04a10f8SKris Kennaway  */
11a04a10f8SKris Kennaway 
12a04a10f8SKris Kennaway #include "includes.h"
13db1cb46cSKris Kennaway RCSID("$OpenBSD: session.c,v 1.15 2000/05/30 17:23:37 markus Exp $");
14a04a10f8SKris Kennaway 
15a04a10f8SKris Kennaway #include "xmalloc.h"
16a04a10f8SKris Kennaway #include "ssh.h"
17a04a10f8SKris Kennaway #include "pty.h"
18a04a10f8SKris Kennaway #include "packet.h"
19a04a10f8SKris Kennaway #include "buffer.h"
20a04a10f8SKris Kennaway #include "cipher.h"
21a04a10f8SKris Kennaway #include "mpaux.h"
22a04a10f8SKris Kennaway #include "servconf.h"
23a04a10f8SKris Kennaway #include "uidswap.h"
24a04a10f8SKris Kennaway #include "compat.h"
25a04a10f8SKris Kennaway #include "channels.h"
26a04a10f8SKris Kennaway #include "nchan.h"
27a04a10f8SKris Kennaway 
28a04a10f8SKris Kennaway #include "bufaux.h"
29a04a10f8SKris Kennaway #include "ssh2.h"
30a04a10f8SKris Kennaway #include "auth.h"
31a04a10f8SKris Kennaway 
32e8aafc91SKris Kennaway #ifdef __FreeBSD__
33e8aafc91SKris Kennaway #define	LOGIN_CAP
34e8aafc91SKris Kennaway #define _PATH_CHPASS "/usr/bin/passwd"
35e8aafc91SKris Kennaway #endif /* __FreeBSD__ */
36e8aafc91SKris Kennaway 
37e8aafc91SKris Kennaway #ifdef LOGIN_CAP
38e8aafc91SKris Kennaway #include <login_cap.h>
39e8aafc91SKris Kennaway #endif /* LOGIN_CAP */
40e8aafc91SKris Kennaway 
41b787acb5SKris Kennaway #ifdef KRB5
42b787acb5SKris Kennaway extern krb5_context ssh_context;
43b787acb5SKris Kennaway #endif
44b787acb5SKris Kennaway 
45a04a10f8SKris Kennaway /* types */
46a04a10f8SKris Kennaway 
47a04a10f8SKris Kennaway #define TTYSZ 64
48a04a10f8SKris Kennaway typedef struct Session Session;
49a04a10f8SKris Kennaway struct Session {
50a04a10f8SKris Kennaway 	int	used;
51a04a10f8SKris Kennaway 	int	self;
52a04a10f8SKris Kennaway 	int	extended;
53a04a10f8SKris Kennaway 	struct	passwd *pw;
54a04a10f8SKris Kennaway 	pid_t	pid;
55a04a10f8SKris Kennaway 	/* tty */
56a04a10f8SKris Kennaway 	char	*term;
57a04a10f8SKris Kennaway 	int	ptyfd, ttyfd, ptymaster;
58a04a10f8SKris Kennaway 	int	row, col, xpixel, ypixel;
59a04a10f8SKris Kennaway 	char	tty[TTYSZ];
60a04a10f8SKris Kennaway 	/* X11 */
61a04a10f8SKris Kennaway 	char	*display;
62a04a10f8SKris Kennaway 	int	screen;
63a04a10f8SKris Kennaway 	char	*auth_proto;
64a04a10f8SKris Kennaway 	char	*auth_data;
65a04a10f8SKris Kennaway 	int	single_connection;
66a04a10f8SKris Kennaway 	/* proto 2 */
67a04a10f8SKris Kennaway 	int	chanid;
68a04a10f8SKris Kennaway };
69a04a10f8SKris Kennaway 
70a04a10f8SKris Kennaway /* func */
71a04a10f8SKris Kennaway 
72a04a10f8SKris Kennaway Session *session_new(void);
73a04a10f8SKris Kennaway void	session_set_fds(Session *s, int fdin, int fdout, int fderr);
74a04a10f8SKris Kennaway void	session_pty_cleanup(Session *s);
75a04a10f8SKris Kennaway void	session_proctitle(Session *s);
76a04a10f8SKris Kennaway void	do_exec_pty(Session *s, const char *command, struct passwd * pw);
77a04a10f8SKris Kennaway void	do_exec_no_pty(Session *s, const char *command, struct passwd * pw);
78a04a10f8SKris Kennaway 
79a04a10f8SKris Kennaway void
80a04a10f8SKris Kennaway do_child(const char *command, struct passwd * pw, const char *term,
81a04a10f8SKris Kennaway     const char *display, const char *auth_proto,
82a04a10f8SKris Kennaway     const char *auth_data, const char *ttyname);
83a04a10f8SKris Kennaway 
84a04a10f8SKris Kennaway /* import */
85a04a10f8SKris Kennaway extern ServerOptions options;
86a04a10f8SKris Kennaway extern char *__progname;
87a04a10f8SKris Kennaway extern int log_stderr;
88a04a10f8SKris Kennaway extern int debug_flag;
89a04a10f8SKris Kennaway 
90a04a10f8SKris Kennaway /* Local Xauthority file. */
91a04a10f8SKris Kennaway static char *xauthfile;
92a04a10f8SKris Kennaway 
93a04a10f8SKris Kennaway /* data */
94a04a10f8SKris Kennaway #define MAX_SESSIONS 10
95a04a10f8SKris Kennaway Session	sessions[MAX_SESSIONS];
96a04a10f8SKris Kennaway 
97a04a10f8SKris Kennaway /* Flags set in auth-rsa from authorized_keys flags.  These are set in auth-rsa.c. */
98a04a10f8SKris Kennaway int no_port_forwarding_flag = 0;
99a04a10f8SKris Kennaway int no_agent_forwarding_flag = 0;
100a04a10f8SKris Kennaway int no_x11_forwarding_flag = 0;
101a04a10f8SKris Kennaway int no_pty_flag = 0;
102a04a10f8SKris Kennaway 
103a04a10f8SKris Kennaway /* RSA authentication "command=" option. */
104a04a10f8SKris Kennaway char *forced_command = NULL;
105a04a10f8SKris Kennaway 
106a04a10f8SKris Kennaway /* RSA authentication "environment=" options. */
107a04a10f8SKris Kennaway struct envstring *custom_environment = NULL;
108a04a10f8SKris Kennaway 
109a04a10f8SKris Kennaway /*
110a04a10f8SKris Kennaway  * Remove local Xauthority file.
111a04a10f8SKris Kennaway  */
112a04a10f8SKris Kennaway void
113a04a10f8SKris Kennaway xauthfile_cleanup_proc(void *ignore)
114a04a10f8SKris Kennaway {
115a04a10f8SKris Kennaway 	debug("xauthfile_cleanup_proc called");
116a04a10f8SKris Kennaway 
117a04a10f8SKris Kennaway 	if (xauthfile != NULL) {
118a04a10f8SKris Kennaway 		char *p;
119a04a10f8SKris Kennaway 		unlink(xauthfile);
120a04a10f8SKris Kennaway 		p = strrchr(xauthfile, '/');
121a04a10f8SKris Kennaway 		if (p != NULL) {
122a04a10f8SKris Kennaway 			*p = '\0';
123a04a10f8SKris Kennaway 			rmdir(xauthfile);
124a04a10f8SKris Kennaway 		}
125a04a10f8SKris Kennaway 		xfree(xauthfile);
126a04a10f8SKris Kennaway 		xauthfile = NULL;
127a04a10f8SKris Kennaway 	}
128a04a10f8SKris Kennaway }
129a04a10f8SKris Kennaway 
130a04a10f8SKris Kennaway /*
131a04a10f8SKris Kennaway  * Function to perform cleanup if we get aborted abnormally (e.g., due to a
132a04a10f8SKris Kennaway  * dropped connection).
133a04a10f8SKris Kennaway  */
134a04a10f8SKris Kennaway void
135a04a10f8SKris Kennaway pty_cleanup_proc(void *session)
136a04a10f8SKris Kennaway {
137a04a10f8SKris Kennaway 	Session *s=session;
138a04a10f8SKris Kennaway 	if (s == NULL)
139a04a10f8SKris Kennaway 		fatal("pty_cleanup_proc: no session");
140a04a10f8SKris Kennaway 	debug("pty_cleanup_proc: %s", s->tty);
141a04a10f8SKris Kennaway 
142a04a10f8SKris Kennaway 	if (s->pid != 0) {
143a04a10f8SKris Kennaway 		/* Record that the user has logged out. */
144a04a10f8SKris Kennaway 		record_logout(s->pid, s->tty);
145a04a10f8SKris Kennaway 	}
146a04a10f8SKris Kennaway 
147a04a10f8SKris Kennaway 	/* Release the pseudo-tty. */
148a04a10f8SKris Kennaway 	pty_release(s->tty);
149a04a10f8SKris Kennaway }
150a04a10f8SKris Kennaway 
151a04a10f8SKris Kennaway /*
152a04a10f8SKris Kennaway  * Prepares for an interactive session.  This is called after the user has
153a04a10f8SKris Kennaway  * been successfully authenticated.  During this message exchange, pseudo
154a04a10f8SKris Kennaway  * terminals are allocated, X11, TCP/IP, and authentication agent forwardings
155a04a10f8SKris Kennaway  * are requested, etc.
156a04a10f8SKris Kennaway  */
157a04a10f8SKris Kennaway void
158a04a10f8SKris Kennaway do_authenticated(struct passwd * pw)
159a04a10f8SKris Kennaway {
160a04a10f8SKris Kennaway 	Session *s;
161a04a10f8SKris Kennaway 	int type;
162a04a10f8SKris Kennaway 	int compression_level = 0, enable_compression_after_reply = 0;
163a04a10f8SKris Kennaway 	int have_pty = 0;
164a04a10f8SKris Kennaway 	char *command;
165a04a10f8SKris Kennaway 	int n_bytes;
166a04a10f8SKris Kennaway 	int plen;
167a04a10f8SKris Kennaway 	unsigned int proto_len, data_len, dlen;
168a04a10f8SKris Kennaway 
169a04a10f8SKris Kennaway 	/*
170a04a10f8SKris Kennaway 	 * Cancel the alarm we set to limit the time taken for
171a04a10f8SKris Kennaway 	 * authentication.
172a04a10f8SKris Kennaway 	 */
173a04a10f8SKris Kennaway 	alarm(0);
174a04a10f8SKris Kennaway 
175a04a10f8SKris Kennaway 	/*
176a04a10f8SKris Kennaway 	 * Inform the channel mechanism that we are the server side and that
177a04a10f8SKris Kennaway 	 * the client may request to connect to any port at all. (The user
178a04a10f8SKris Kennaway 	 * could do it anyway, and we wouldn\'t know what is permitted except
179a04a10f8SKris Kennaway 	 * by the client telling us, so we can equally well trust the client
180a04a10f8SKris Kennaway 	 * not to request anything bogus.)
181a04a10f8SKris Kennaway 	 */
182a04a10f8SKris Kennaway 	if (!no_port_forwarding_flag)
183a04a10f8SKris Kennaway 		channel_permit_all_opens();
184a04a10f8SKris Kennaway 
185a04a10f8SKris Kennaway 	s = session_new();
186a04a10f8SKris Kennaway 	s->pw = pw;
187a04a10f8SKris Kennaway 
188a04a10f8SKris Kennaway 	/*
189a04a10f8SKris Kennaway 	 * We stay in this loop until the client requests to execute a shell
190a04a10f8SKris Kennaway 	 * or a command.
191a04a10f8SKris Kennaway 	 */
192a04a10f8SKris Kennaway 	for (;;) {
193a04a10f8SKris Kennaway 		int success = 0;
194a04a10f8SKris Kennaway 
195a04a10f8SKris Kennaway 		/* Get a packet from the client. */
196a04a10f8SKris Kennaway 		type = packet_read(&plen);
197a04a10f8SKris Kennaway 
198a04a10f8SKris Kennaway 		/* Process the packet. */
199a04a10f8SKris Kennaway 		switch (type) {
200a04a10f8SKris Kennaway 		case SSH_CMSG_REQUEST_COMPRESSION:
201a04a10f8SKris Kennaway 			packet_integrity_check(plen, 4, type);
202a04a10f8SKris Kennaway 			compression_level = packet_get_int();
203a04a10f8SKris Kennaway 			if (compression_level < 1 || compression_level > 9) {
204a04a10f8SKris Kennaway 				packet_send_debug("Received illegal compression level %d.",
205a04a10f8SKris Kennaway 				     compression_level);
206a04a10f8SKris Kennaway 				break;
207a04a10f8SKris Kennaway 			}
208a04a10f8SKris Kennaway 			/* Enable compression after we have responded with SUCCESS. */
209a04a10f8SKris Kennaway 			enable_compression_after_reply = 1;
210a04a10f8SKris Kennaway 			success = 1;
211a04a10f8SKris Kennaway 			break;
212a04a10f8SKris Kennaway 
213a04a10f8SKris Kennaway 		case SSH_CMSG_REQUEST_PTY:
214a04a10f8SKris Kennaway 			if (no_pty_flag) {
215a04a10f8SKris Kennaway 				debug("Allocating a pty not permitted for this authentication.");
216a04a10f8SKris Kennaway 				break;
217a04a10f8SKris Kennaway 			}
218a04a10f8SKris Kennaway 			if (have_pty)
219a04a10f8SKris Kennaway 				packet_disconnect("Protocol error: you already have a pty.");
220a04a10f8SKris Kennaway 
221a04a10f8SKris Kennaway 			debug("Allocating pty.");
222a04a10f8SKris Kennaway 
223a04a10f8SKris Kennaway 			/* Allocate a pty and open it. */
224a04a10f8SKris Kennaway 			if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty,
225a04a10f8SKris Kennaway 			    sizeof(s->tty))) {
226a04a10f8SKris Kennaway 				error("Failed to allocate pty.");
227a04a10f8SKris Kennaway 				break;
228a04a10f8SKris Kennaway 			}
229a04a10f8SKris Kennaway 			fatal_add_cleanup(pty_cleanup_proc, (void *)s);
230a04a10f8SKris Kennaway 			pty_setowner(pw, s->tty);
231a04a10f8SKris Kennaway 
232a04a10f8SKris Kennaway 			/* Get TERM from the packet.  Note that the value may be of arbitrary length. */
233a04a10f8SKris Kennaway 			s->term = packet_get_string(&dlen);
234a04a10f8SKris Kennaway 			packet_integrity_check(dlen, strlen(s->term), type);
235a04a10f8SKris Kennaway 			/* packet_integrity_check(plen, 4 + dlen + 4*4 + n_bytes, type); */
236a04a10f8SKris Kennaway 			/* Remaining bytes */
237a04a10f8SKris Kennaway 			n_bytes = plen - (4 + dlen + 4 * 4);
238a04a10f8SKris Kennaway 
239a04a10f8SKris Kennaway 			if (strcmp(s->term, "") == 0) {
240a04a10f8SKris Kennaway 				xfree(s->term);
241a04a10f8SKris Kennaway 				s->term = NULL;
242a04a10f8SKris Kennaway 			}
243a04a10f8SKris Kennaway 			/* Get window size from the packet. */
244a04a10f8SKris Kennaway 			s->row = packet_get_int();
245a04a10f8SKris Kennaway 			s->col = packet_get_int();
246a04a10f8SKris Kennaway 			s->xpixel = packet_get_int();
247a04a10f8SKris Kennaway 			s->ypixel = packet_get_int();
248a04a10f8SKris Kennaway 			pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
249a04a10f8SKris Kennaway 
250a04a10f8SKris Kennaway 			/* Get tty modes from the packet. */
251a04a10f8SKris Kennaway 			tty_parse_modes(s->ttyfd, &n_bytes);
252a04a10f8SKris Kennaway 			packet_integrity_check(plen, 4 + dlen + 4 * 4 + n_bytes, type);
253a04a10f8SKris Kennaway 
254a04a10f8SKris Kennaway 			session_proctitle(s);
255a04a10f8SKris Kennaway 
256a04a10f8SKris Kennaway 			/* Indicate that we now have a pty. */
257a04a10f8SKris Kennaway 			success = 1;
258a04a10f8SKris Kennaway 			have_pty = 1;
259a04a10f8SKris Kennaway 			break;
260a04a10f8SKris Kennaway 
261a04a10f8SKris Kennaway 		case SSH_CMSG_X11_REQUEST_FORWARDING:
262a04a10f8SKris Kennaway 			if (!options.x11_forwarding) {
263a04a10f8SKris Kennaway 				packet_send_debug("X11 forwarding disabled in server configuration file.");
264a04a10f8SKris Kennaway 				break;
265a04a10f8SKris Kennaway 			}
266a04a10f8SKris Kennaway #ifdef XAUTH_PATH
267a04a10f8SKris Kennaway 			if (no_x11_forwarding_flag) {
268a04a10f8SKris Kennaway 				packet_send_debug("X11 forwarding not permitted for this authentication.");
269a04a10f8SKris Kennaway 				break;
270a04a10f8SKris Kennaway 			}
271a04a10f8SKris Kennaway 			debug("Received request for X11 forwarding with auth spoofing.");
272a04a10f8SKris Kennaway 			if (s->display != NULL)
273a04a10f8SKris Kennaway 				packet_disconnect("Protocol error: X11 display already set.");
274a04a10f8SKris Kennaway 
275a04a10f8SKris Kennaway 			s->auth_proto = packet_get_string(&proto_len);
276a04a10f8SKris Kennaway 			s->auth_data = packet_get_string(&data_len);
277a04a10f8SKris Kennaway 			packet_integrity_check(plen, 4 + proto_len + 4 + data_len + 4, type);
278a04a10f8SKris Kennaway 
279a04a10f8SKris Kennaway 			if (packet_get_protocol_flags() & SSH_PROTOFLAG_SCREEN_NUMBER)
280a04a10f8SKris Kennaway 				s->screen = packet_get_int();
281a04a10f8SKris Kennaway 			else
282a04a10f8SKris Kennaway 				s->screen = 0;
283a04a10f8SKris Kennaway 			s->display = x11_create_display_inet(s->screen, options.x11_display_offset);
284a04a10f8SKris Kennaway 
285a04a10f8SKris Kennaway 			if (s->display == NULL)
286a04a10f8SKris Kennaway 				break;
287a04a10f8SKris Kennaway 
288a04a10f8SKris Kennaway 			/* Setup to always have a local .Xauthority. */
289a04a10f8SKris Kennaway 			xauthfile = xmalloc(MAXPATHLEN);
290a04a10f8SKris Kennaway 			strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
291a04a10f8SKris Kennaway 			temporarily_use_uid(pw->pw_uid);
292a04a10f8SKris Kennaway 			if (mkdtemp(xauthfile) == NULL) {
293a04a10f8SKris Kennaway 				restore_uid();
294a04a10f8SKris Kennaway 				error("private X11 dir: mkdtemp %s failed: %s",
295a04a10f8SKris Kennaway 				    xauthfile, strerror(errno));
296a04a10f8SKris Kennaway 				xfree(xauthfile);
297a04a10f8SKris Kennaway 				xauthfile = NULL;
298a04a10f8SKris Kennaway 				/* XXXX remove listening channels */
299a04a10f8SKris Kennaway 				break;
300a04a10f8SKris Kennaway 			}
301a04a10f8SKris Kennaway 			strlcat(xauthfile, "/cookies", MAXPATHLEN);
302a04a10f8SKris Kennaway 			open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600);
303a04a10f8SKris Kennaway 			restore_uid();
304a04a10f8SKris Kennaway 			fatal_add_cleanup(xauthfile_cleanup_proc, NULL);
305a04a10f8SKris Kennaway 			success = 1;
306a04a10f8SKris Kennaway 			break;
307a04a10f8SKris Kennaway #else /* XAUTH_PATH */
308a04a10f8SKris Kennaway 			packet_send_debug("No xauth program; cannot forward with spoofing.");
309a04a10f8SKris Kennaway 			break;
310a04a10f8SKris Kennaway #endif /* XAUTH_PATH */
311a04a10f8SKris Kennaway 
312a04a10f8SKris Kennaway 		case SSH_CMSG_AGENT_REQUEST_FORWARDING:
313a04a10f8SKris Kennaway 			if (no_agent_forwarding_flag || compat13) {
314a04a10f8SKris Kennaway 				debug("Authentication agent forwarding not permitted for this authentication.");
315a04a10f8SKris Kennaway 				break;
316a04a10f8SKris Kennaway 			}
317a04a10f8SKris Kennaway 			debug("Received authentication agent forwarding request.");
318db1cb46cSKris Kennaway 			success = auth_input_request_forwarding(pw);
319a04a10f8SKris Kennaway 			break;
320a04a10f8SKris Kennaway 
321a04a10f8SKris Kennaway 		case SSH_CMSG_PORT_FORWARD_REQUEST:
322a04a10f8SKris Kennaway 			if (no_port_forwarding_flag) {
323a04a10f8SKris Kennaway 				debug("Port forwarding not permitted for this authentication.");
324a04a10f8SKris Kennaway 				break;
325a04a10f8SKris Kennaway 			}
326a04a10f8SKris Kennaway 			debug("Received TCP/IP port forwarding request.");
327a04a10f8SKris Kennaway 			channel_input_port_forward_request(pw->pw_uid == 0, options.gateway_ports);
328a04a10f8SKris Kennaway 			success = 1;
329a04a10f8SKris Kennaway 			break;
330a04a10f8SKris Kennaway 
331a04a10f8SKris Kennaway 		case SSH_CMSG_MAX_PACKET_SIZE:
332a04a10f8SKris Kennaway 			if (packet_set_maxsize(packet_get_int()) > 0)
333a04a10f8SKris Kennaway 				success = 1;
334a04a10f8SKris Kennaway 			break;
335a04a10f8SKris Kennaway 
336a04a10f8SKris Kennaway 		case SSH_CMSG_EXEC_SHELL:
337a04a10f8SKris Kennaway 		case SSH_CMSG_EXEC_CMD:
338a04a10f8SKris Kennaway 			/* Set interactive/non-interactive mode. */
339a04a10f8SKris Kennaway 			packet_set_interactive(have_pty || s->display != NULL,
340a04a10f8SKris Kennaway 			    options.keepalives);
341a04a10f8SKris Kennaway 
342a04a10f8SKris Kennaway 			if (type == SSH_CMSG_EXEC_CMD) {
343a04a10f8SKris Kennaway 				command = packet_get_string(&dlen);
344a04a10f8SKris Kennaway 				debug("Exec command '%.500s'", command);
345a04a10f8SKris Kennaway 				packet_integrity_check(plen, 4 + dlen, type);
346a04a10f8SKris Kennaway 			} else {
347a04a10f8SKris Kennaway 				command = NULL;
348a04a10f8SKris Kennaway 				packet_integrity_check(plen, 0, type);
349a04a10f8SKris Kennaway 			}
350a04a10f8SKris Kennaway 			if (forced_command != NULL) {
351a04a10f8SKris Kennaway 				command = forced_command;
352a04a10f8SKris Kennaway 				debug("Forced command '%.500s'", forced_command);
353a04a10f8SKris Kennaway 			}
354a04a10f8SKris Kennaway 			if (have_pty)
355a04a10f8SKris Kennaway 				do_exec_pty(s, command, pw);
356a04a10f8SKris Kennaway 			else
357a04a10f8SKris Kennaway 				do_exec_no_pty(s, command, pw);
358a04a10f8SKris Kennaway 
359a04a10f8SKris Kennaway 			if (command != NULL)
360a04a10f8SKris Kennaway 				xfree(command);
361a04a10f8SKris Kennaway 			/* Cleanup user's local Xauthority file. */
362a04a10f8SKris Kennaway 			if (xauthfile)
363a04a10f8SKris Kennaway 				xauthfile_cleanup_proc(NULL);
364a04a10f8SKris Kennaway 			return;
365a04a10f8SKris Kennaway 
366a04a10f8SKris Kennaway 		default:
367a04a10f8SKris Kennaway 			/*
368a04a10f8SKris Kennaway 			 * Any unknown messages in this phase are ignored,
369a04a10f8SKris Kennaway 			 * and a failure message is returned.
370a04a10f8SKris Kennaway 			 */
371a04a10f8SKris Kennaway 			log("Unknown packet type received after authentication: %d", type);
372a04a10f8SKris Kennaway 		}
373a04a10f8SKris Kennaway 		packet_start(success ? SSH_SMSG_SUCCESS : SSH_SMSG_FAILURE);
374a04a10f8SKris Kennaway 		packet_send();
375a04a10f8SKris Kennaway 		packet_write_wait();
376a04a10f8SKris Kennaway 
377a04a10f8SKris Kennaway 		/* Enable compression now that we have replied if appropriate. */
378a04a10f8SKris Kennaway 		if (enable_compression_after_reply) {
379a04a10f8SKris Kennaway 			enable_compression_after_reply = 0;
380a04a10f8SKris Kennaway 			packet_start_compression(compression_level);
381a04a10f8SKris Kennaway 		}
382a04a10f8SKris Kennaway 	}
383a04a10f8SKris Kennaway }
384a04a10f8SKris Kennaway 
385a04a10f8SKris Kennaway /*
386a04a10f8SKris Kennaway  * This is called to fork and execute a command when we have no tty.  This
387a04a10f8SKris Kennaway  * will call do_child from the child, and server_loop from the parent after
388a04a10f8SKris Kennaway  * setting up file descriptors and such.
389a04a10f8SKris Kennaway  */
390a04a10f8SKris Kennaway void
391a04a10f8SKris Kennaway do_exec_no_pty(Session *s, const char *command, struct passwd * pw)
392a04a10f8SKris Kennaway {
393a04a10f8SKris Kennaway 	int pid;
394a04a10f8SKris Kennaway 
395a04a10f8SKris Kennaway #ifdef USE_PIPES
396a04a10f8SKris Kennaway 	int pin[2], pout[2], perr[2];
397a04a10f8SKris Kennaway 	/* Allocate pipes for communicating with the program. */
398a04a10f8SKris Kennaway 	if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0)
399a04a10f8SKris Kennaway 		packet_disconnect("Could not create pipes: %.100s",
400a04a10f8SKris Kennaway 				  strerror(errno));
401a04a10f8SKris Kennaway #else /* USE_PIPES */
402a04a10f8SKris Kennaway 	int inout[2], err[2];
403a04a10f8SKris Kennaway 	/* Uses socket pairs to communicate with the program. */
404a04a10f8SKris Kennaway 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 ||
405a04a10f8SKris Kennaway 	    socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0)
406a04a10f8SKris Kennaway 		packet_disconnect("Could not create socket pairs: %.100s",
407a04a10f8SKris Kennaway 				  strerror(errno));
408a04a10f8SKris Kennaway #endif /* USE_PIPES */
409a04a10f8SKris Kennaway 	if (s == NULL)
410a04a10f8SKris Kennaway 		fatal("do_exec_no_pty: no session");
411a04a10f8SKris Kennaway 
412a04a10f8SKris Kennaway 	session_proctitle(s);
413a04a10f8SKris Kennaway 
414a04a10f8SKris Kennaway 	/* Fork the child. */
415a04a10f8SKris Kennaway 	if ((pid = fork()) == 0) {
416a04a10f8SKris Kennaway 		/* Child.  Reinitialize the log since the pid has changed. */
417a04a10f8SKris Kennaway 		log_init(__progname, options.log_level, options.log_facility, log_stderr);
418a04a10f8SKris Kennaway 
419a04a10f8SKris Kennaway 		/*
420a04a10f8SKris Kennaway 		 * Create a new session and process group since the 4.4BSD
421a04a10f8SKris Kennaway 		 * setlogin() affects the entire process group.
422a04a10f8SKris Kennaway 		 */
423a04a10f8SKris Kennaway 		if (setsid() < 0)
424a04a10f8SKris Kennaway 			error("setsid failed: %.100s", strerror(errno));
425a04a10f8SKris Kennaway 
426a04a10f8SKris Kennaway #ifdef USE_PIPES
427a04a10f8SKris Kennaway 		/*
428a04a10f8SKris Kennaway 		 * Redirect stdin.  We close the parent side of the socket
429a04a10f8SKris Kennaway 		 * pair, and make the child side the standard input.
430a04a10f8SKris Kennaway 		 */
431a04a10f8SKris Kennaway 		close(pin[1]);
432a04a10f8SKris Kennaway 		if (dup2(pin[0], 0) < 0)
433a04a10f8SKris Kennaway 			perror("dup2 stdin");
434a04a10f8SKris Kennaway 		close(pin[0]);
435a04a10f8SKris Kennaway 
436a04a10f8SKris Kennaway 		/* Redirect stdout. */
437a04a10f8SKris Kennaway 		close(pout[0]);
438a04a10f8SKris Kennaway 		if (dup2(pout[1], 1) < 0)
439a04a10f8SKris Kennaway 			perror("dup2 stdout");
440a04a10f8SKris Kennaway 		close(pout[1]);
441a04a10f8SKris Kennaway 
442a04a10f8SKris Kennaway 		/* Redirect stderr. */
443a04a10f8SKris Kennaway 		close(perr[0]);
444a04a10f8SKris Kennaway 		if (dup2(perr[1], 2) < 0)
445a04a10f8SKris Kennaway 			perror("dup2 stderr");
446a04a10f8SKris Kennaway 		close(perr[1]);
447a04a10f8SKris Kennaway #else /* USE_PIPES */
448a04a10f8SKris Kennaway 		/*
449a04a10f8SKris Kennaway 		 * Redirect stdin, stdout, and stderr.  Stdin and stdout will
450a04a10f8SKris Kennaway 		 * use the same socket, as some programs (particularly rdist)
451a04a10f8SKris Kennaway 		 * seem to depend on it.
452a04a10f8SKris Kennaway 		 */
453a04a10f8SKris Kennaway 		close(inout[1]);
454a04a10f8SKris Kennaway 		close(err[1]);
455a04a10f8SKris Kennaway 		if (dup2(inout[0], 0) < 0)	/* stdin */
456a04a10f8SKris Kennaway 			perror("dup2 stdin");
457a04a10f8SKris Kennaway 		if (dup2(inout[0], 1) < 0)	/* stdout.  Note: same socket as stdin. */
458a04a10f8SKris Kennaway 			perror("dup2 stdout");
459a04a10f8SKris Kennaway 		if (dup2(err[0], 2) < 0)	/* stderr */
460a04a10f8SKris Kennaway 			perror("dup2 stderr");
461a04a10f8SKris Kennaway #endif /* USE_PIPES */
462a04a10f8SKris Kennaway 
463a04a10f8SKris Kennaway 		/* Do processing for the child (exec command etc). */
464a04a10f8SKris Kennaway 		do_child(command, pw, NULL, s->display, s->auth_proto, s->auth_data, NULL);
465a04a10f8SKris Kennaway 		/* NOTREACHED */
466a04a10f8SKris Kennaway 	}
467a04a10f8SKris Kennaway 	if (pid < 0)
468a04a10f8SKris Kennaway 		packet_disconnect("fork failed: %.100s", strerror(errno));
469a04a10f8SKris Kennaway 	s->pid = pid;
470a04a10f8SKris Kennaway #ifdef USE_PIPES
471a04a10f8SKris Kennaway 	/* We are the parent.  Close the child sides of the pipes. */
472a04a10f8SKris Kennaway 	close(pin[0]);
473a04a10f8SKris Kennaway 	close(pout[1]);
474a04a10f8SKris Kennaway 	close(perr[1]);
475a04a10f8SKris Kennaway 
476a04a10f8SKris Kennaway 	if (compat20) {
477a04a10f8SKris Kennaway 		session_set_fds(s, pin[1], pout[0], s->extended ? perr[0] : -1);
478a04a10f8SKris Kennaway 	} else {
479a04a10f8SKris Kennaway 		/* Enter the interactive session. */
480a04a10f8SKris Kennaway 		server_loop(pid, pin[1], pout[0], perr[0]);
481a04a10f8SKris Kennaway 		/* server_loop has closed pin[1], pout[1], and perr[1]. */
482a04a10f8SKris Kennaway 	}
483a04a10f8SKris Kennaway #else /* USE_PIPES */
484a04a10f8SKris Kennaway 	/* We are the parent.  Close the child sides of the socket pairs. */
485a04a10f8SKris Kennaway 	close(inout[0]);
486a04a10f8SKris Kennaway 	close(err[0]);
487a04a10f8SKris Kennaway 
488a04a10f8SKris Kennaway 	/*
489a04a10f8SKris Kennaway 	 * Enter the interactive session.  Note: server_loop must be able to
490a04a10f8SKris Kennaway 	 * handle the case that fdin and fdout are the same.
491a04a10f8SKris Kennaway 	 */
492a04a10f8SKris Kennaway 	if (compat20) {
493a04a10f8SKris Kennaway 		session_set_fds(s, inout[1], inout[1], s->extended ? err[1] : -1);
494a04a10f8SKris Kennaway 	} else {
495a04a10f8SKris Kennaway 		server_loop(pid, inout[1], inout[1], err[1]);
496a04a10f8SKris Kennaway 		/* server_loop has closed inout[1] and err[1]. */
497a04a10f8SKris Kennaway 	}
498a04a10f8SKris Kennaway #endif /* USE_PIPES */
499a04a10f8SKris Kennaway }
500a04a10f8SKris Kennaway 
501a04a10f8SKris Kennaway /*
502a04a10f8SKris Kennaway  * This is called to fork and execute a command when we have a tty.  This
503a04a10f8SKris Kennaway  * will call do_child from the child, and server_loop from the parent after
504a04a10f8SKris Kennaway  * setting up file descriptors, controlling tty, updating wtmp, utmp,
505a04a10f8SKris Kennaway  * lastlog, and other such operations.
506a04a10f8SKris Kennaway  */
507a04a10f8SKris Kennaway void
508a04a10f8SKris Kennaway do_exec_pty(Session *s, const char *command, struct passwd * pw)
509a04a10f8SKris Kennaway {
510a04a10f8SKris Kennaway 	FILE *f;
511a04a10f8SKris Kennaway 	char buf[100], *time_string;
512a04a10f8SKris Kennaway 	char line[256];
513a04a10f8SKris Kennaway 	const char *hostname;
514a04a10f8SKris Kennaway 	int fdout, ptyfd, ttyfd, ptymaster;
515a04a10f8SKris Kennaway 	int quiet_login;
516a04a10f8SKris Kennaway 	pid_t pid;
517a04a10f8SKris Kennaway 	socklen_t fromlen;
518a04a10f8SKris Kennaway 	struct sockaddr_storage from;
519a04a10f8SKris Kennaway 	struct stat st;
520a04a10f8SKris Kennaway 	time_t last_login_time;
521e8aafc91SKris Kennaway #ifdef LOGIN_CAP
522e8aafc91SKris Kennaway 	login_cap_t *lc;
523e8aafc91SKris Kennaway 	char *fname;
524e8aafc91SKris Kennaway #endif /* LOGIN_CAP */
525e8aafc91SKris Kennaway #ifdef __FreeBSD__
526e8aafc91SKris Kennaway #define DEFAULT_WARN  (2L * 7L * 86400L)  /* Two weeks */
527e8aafc91SKris Kennaway 	struct timeval tv;
528e8aafc91SKris Kennaway 	time_t warntime = DEFAULT_WARN;
529e8aafc91SKris Kennaway #endif /* __FreeBSD__ */
530a04a10f8SKris Kennaway 
531a04a10f8SKris Kennaway 	if (s == NULL)
532a04a10f8SKris Kennaway 		fatal("do_exec_pty: no session");
533a04a10f8SKris Kennaway 	ptyfd = s->ptyfd;
534a04a10f8SKris Kennaway 	ttyfd = s->ttyfd;
535a04a10f8SKris Kennaway 
536a04a10f8SKris Kennaway 	/* Get remote host name. */
537a04a10f8SKris Kennaway 	hostname = get_canonical_hostname();
538a04a10f8SKris Kennaway 
539a04a10f8SKris Kennaway 	/*
540a04a10f8SKris Kennaway 	 * Get the time when the user last logged in.  Buf will be set to
541a04a10f8SKris Kennaway 	 * contain the hostname the last login was from.
542a04a10f8SKris Kennaway 	 */
543a04a10f8SKris Kennaway 	if (!options.use_login) {
544a04a10f8SKris Kennaway 		last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
545a04a10f8SKris Kennaway 						      buf, sizeof(buf));
546a04a10f8SKris Kennaway 	}
547a04a10f8SKris Kennaway 
548a04a10f8SKris Kennaway 	/* Fork the child. */
549a04a10f8SKris Kennaway 	if ((pid = fork()) == 0) {
550a04a10f8SKris Kennaway 		pid = getpid();
551a04a10f8SKris Kennaway 
552a04a10f8SKris Kennaway 		/* Child.  Reinitialize the log because the pid has
553a04a10f8SKris Kennaway 		   changed. */
554a04a10f8SKris Kennaway 		log_init(__progname, options.log_level, options.log_facility, log_stderr);
555a04a10f8SKris Kennaway 
556a04a10f8SKris Kennaway 		/* Close the master side of the pseudo tty. */
557a04a10f8SKris Kennaway 		close(ptyfd);
558a04a10f8SKris Kennaway 
559a04a10f8SKris Kennaway 		/* Make the pseudo tty our controlling tty. */
560a04a10f8SKris Kennaway 		pty_make_controlling_tty(&ttyfd, s->tty);
561a04a10f8SKris Kennaway 
562a04a10f8SKris Kennaway 		/* Redirect stdin from the pseudo tty. */
563a04a10f8SKris Kennaway 		if (dup2(ttyfd, fileno(stdin)) < 0)
564a04a10f8SKris Kennaway 			error("dup2 stdin failed: %.100s", strerror(errno));
565a04a10f8SKris Kennaway 
566a04a10f8SKris Kennaway 		/* Redirect stdout to the pseudo tty. */
567a04a10f8SKris Kennaway 		if (dup2(ttyfd, fileno(stdout)) < 0)
568a04a10f8SKris Kennaway 			error("dup2 stdin failed: %.100s", strerror(errno));
569a04a10f8SKris Kennaway 
570a04a10f8SKris Kennaway 		/* Redirect stderr to the pseudo tty. */
571a04a10f8SKris Kennaway 		if (dup2(ttyfd, fileno(stderr)) < 0)
572a04a10f8SKris Kennaway 			error("dup2 stdin failed: %.100s", strerror(errno));
573a04a10f8SKris Kennaway 
574a04a10f8SKris Kennaway 		/* Close the extra descriptor for the pseudo tty. */
575a04a10f8SKris Kennaway 		close(ttyfd);
576a04a10f8SKris Kennaway 
577a04a10f8SKris Kennaway /* XXXX ? move to do_child() ??*/
578a04a10f8SKris Kennaway 		/*
579a04a10f8SKris Kennaway 		 * Get IP address of client.  This is needed because we want
580a04a10f8SKris Kennaway 		 * to record where the user logged in from.  If the
581a04a10f8SKris Kennaway 		 * connection is not a socket, let the ip address be 0.0.0.0.
582a04a10f8SKris Kennaway 		 */
583a04a10f8SKris Kennaway 		memset(&from, 0, sizeof(from));
584a04a10f8SKris Kennaway 		if (packet_connection_is_on_socket()) {
585a04a10f8SKris Kennaway 			fromlen = sizeof(from);
586a04a10f8SKris Kennaway 			if (getpeername(packet_get_connection_in(),
587a04a10f8SKris Kennaway 			     (struct sockaddr *) & from, &fromlen) < 0) {
588a04a10f8SKris Kennaway 				debug("getpeername: %.100s", strerror(errno));
589a04a10f8SKris Kennaway 				fatal_cleanup();
590a04a10f8SKris Kennaway 			}
591a04a10f8SKris Kennaway 		}
592a04a10f8SKris Kennaway 		/* Record that there was a login on that terminal. */
593a04a10f8SKris Kennaway 		record_login(pid, s->tty, pw->pw_name, pw->pw_uid, hostname,
594a04a10f8SKris Kennaway 			     (struct sockaddr *)&from);
595a04a10f8SKris Kennaway 
596a04a10f8SKris Kennaway 		/* Check if .hushlogin exists. */
597a04a10f8SKris Kennaway 		snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir);
598a04a10f8SKris Kennaway 		quiet_login = stat(line, &st) >= 0;
599a04a10f8SKris Kennaway 
600e8aafc91SKris Kennaway #ifdef LOGIN_CAP
601e8aafc91SKris Kennaway 		lc = login_getpwclass(pw);
602e8aafc91SKris Kennaway 		if (lc == NULL)
603e8aafc91SKris Kennaway 			lc = login_getclassbyname(NULL, pw);
604e8aafc91SKris Kennaway 		quiet_login = login_getcapbool(lc, "hushlogin", quiet_login);
605e8aafc91SKris Kennaway #endif /* LOGIN_CAP */
606e8aafc91SKris Kennaway 
607e8aafc91SKris Kennaway #ifdef __FreeBSD__
608e8aafc91SKris Kennaway 		if (pw->pw_change || pw->pw_expire)
609e8aafc91SKris Kennaway 			(void)gettimeofday(&tv, NULL);
610e8aafc91SKris Kennaway #ifdef LOGIN_CAP
611e8aafc91SKris Kennaway 		warntime = login_getcaptime(lc, "warnpassword",
612e8aafc91SKris Kennaway 					    DEFAULT_WARN, DEFAULT_WARN);
613e8aafc91SKris Kennaway #endif /* LOGIN_CAP */
614e8aafc91SKris Kennaway 		/*
615e8aafc91SKris Kennaway 		 * If the password change time is set and has passed, give the
616e8aafc91SKris Kennaway 		 * user a password expiry notice and chance to change it.
617e8aafc91SKris Kennaway 		 */
618e8aafc91SKris Kennaway 		if (pw->pw_change != 0) {
619e8aafc91SKris Kennaway 			if (tv.tv_sec >= pw->pw_change) {
620e8aafc91SKris Kennaway 				(void)printf(
621e8aafc91SKris Kennaway 				    "Sorry -- your password has expired.\n");
622e8aafc91SKris Kennaway 				log("%s Password expired - forcing change",
623e8aafc91SKris Kennaway 				    pw->pw_name);
624e8aafc91SKris Kennaway 				command = _PATH_CHPASS;
625e8aafc91SKris Kennaway 			} else if (pw->pw_change - tv.tv_sec < warntime &&
626e8aafc91SKris Kennaway 				   !quiet_login)
627e8aafc91SKris Kennaway 				(void)printf(
628e8aafc91SKris Kennaway 				    "Warning: your password expires on %s",
629e8aafc91SKris Kennaway 				     ctime(&pw->pw_change));
630e8aafc91SKris Kennaway 		}
631e8aafc91SKris Kennaway #ifdef LOGIN_CAP
632e8aafc91SKris Kennaway 		warntime = login_getcaptime(lc, "warnexpire",
633e8aafc91SKris Kennaway 					    DEFAULT_WARN, DEFAULT_WARN);
634e8aafc91SKris Kennaway #endif /* LOGIN_CAP */
635e8aafc91SKris Kennaway 		if (pw->pw_expire) {
636e8aafc91SKris Kennaway 			if (tv.tv_sec >= pw->pw_expire) {
637e8aafc91SKris Kennaway 				(void)printf(
638e8aafc91SKris Kennaway 				    "Sorry -- your account has expired.\n");
639e8aafc91SKris Kennaway 				log(
640e8aafc91SKris Kennaway 		   "LOGIN %.200s REFUSED (EXPIRED) FROM %.200s ON TTY %.200s",
641e8aafc91SKris Kennaway 					pw->pw_name, hostname, ttyname);
642e8aafc91SKris Kennaway 				exit(254);
643e8aafc91SKris Kennaway 			} else if (pw->pw_expire - tv.tv_sec < warntime &&
644e8aafc91SKris Kennaway 				   !quiet_login)
645e8aafc91SKris Kennaway 				(void)printf(
646e8aafc91SKris Kennaway 				    "Warning: your account expires on %s",
647e8aafc91SKris Kennaway 				     ctime(&pw->pw_expire));
648e8aafc91SKris Kennaway 		}
649e8aafc91SKris Kennaway #endif /* __FreeBSD__ */
650e8aafc91SKris Kennaway #ifdef LOGIN_CAP
651e8aafc91SKris Kennaway 		if (!auth_ttyok(lc, ttyname)) {
652e8aafc91SKris Kennaway 			(void)printf("Permission denied.\n");
653e8aafc91SKris Kennaway 			log(
654e8aafc91SKris Kennaway 		       "LOGIN %.200s REFUSED (TTY) FROM %.200s ON TTY %.200s",
655e8aafc91SKris Kennaway 			    pw->pw_name, hostname, ttyname);
656e8aafc91SKris Kennaway 			exit(254);
657e8aafc91SKris Kennaway 		}
658e8aafc91SKris Kennaway #endif /* LOGIN_CAP */
659e8aafc91SKris Kennaway 
660a04a10f8SKris Kennaway 		/*
661a04a10f8SKris Kennaway 		 * If the user has logged in before, display the time of last
662a04a10f8SKris Kennaway 		 * login. However, don't display anything extra if a command
663a04a10f8SKris Kennaway 		 * has been specified (so that ssh can be used to execute
664a04a10f8SKris Kennaway 		 * commands on a remote machine without users knowing they
665a04a10f8SKris Kennaway 		 * are going to another machine). Login(1) will do this for
666a04a10f8SKris Kennaway 		 * us as well, so check if login(1) is used
667a04a10f8SKris Kennaway 		 */
668a04a10f8SKris Kennaway 		if (command == NULL && last_login_time != 0 && !quiet_login &&
669a04a10f8SKris Kennaway 		    !options.use_login) {
670a04a10f8SKris Kennaway 			/* Convert the date to a string. */
671a04a10f8SKris Kennaway 			time_string = ctime(&last_login_time);
672a04a10f8SKris Kennaway 			/* Remove the trailing newline. */
673a04a10f8SKris Kennaway 			if (strchr(time_string, '\n'))
674a04a10f8SKris Kennaway 				*strchr(time_string, '\n') = 0;
675a04a10f8SKris Kennaway 			/* Display the last login time.  Host if displayed
676a04a10f8SKris Kennaway 			   if known. */
677a04a10f8SKris Kennaway 			if (strcmp(buf, "") == 0)
678a04a10f8SKris Kennaway 				printf("Last login: %s\r\n", time_string);
679a04a10f8SKris Kennaway 			else
680a04a10f8SKris Kennaway 				printf("Last login: %s from %s\r\n", time_string, buf);
681a04a10f8SKris Kennaway 		}
682e8aafc91SKris Kennaway 
683e8aafc91SKris Kennaway #ifdef LOGIN_CAP
684e8aafc91SKris Kennaway 		if (command == NULL && !quiet_login && !options.use_login) {
685e8aafc91SKris Kennaway 			fname = login_getcapstr(lc, "copyright", NULL, NULL);
686e8aafc91SKris Kennaway 			if (fname != NULL && (f = fopen(fname, "r")) != NULL) {
687e8aafc91SKris Kennaway 				while (fgets(line, sizeof(line), f) != NULL)
688e8aafc91SKris Kennaway 					fputs(line, stdout);
689e8aafc91SKris Kennaway 				fclose(f);
690e8aafc91SKris Kennaway 			} else
691e8aafc91SKris Kennaway 				(void)printf("%s\n\t%s %s\n",
692e8aafc91SKris Kennaway 		"Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
693e8aafc91SKris Kennaway 		    "The Regents of the University of California. ",
694e8aafc91SKris Kennaway 		    "All rights reserved.");
695e8aafc91SKris Kennaway 		}
696e8aafc91SKris Kennaway #endif /* LOGIN_CAP */
697e8aafc91SKris Kennaway 
698a04a10f8SKris Kennaway 		/*
699a04a10f8SKris Kennaway 		 * Print /etc/motd unless a command was specified or printing
700a04a10f8SKris Kennaway 		 * it was disabled in server options or login(1) will be
701a04a10f8SKris Kennaway 		 * used.  Note that some machines appear to print it in
702a04a10f8SKris Kennaway 		 * /etc/profile or similar.
703a04a10f8SKris Kennaway 		 */
704a04a10f8SKris Kennaway 		if (command == NULL && options.print_motd && !quiet_login &&
705a04a10f8SKris Kennaway 		    !options.use_login) {
706e8aafc91SKris Kennaway #ifdef LOGIN_CAP
707e8aafc91SKris Kennaway 			fname = login_getcapstr(lc, "welcome", NULL, NULL);
708e8aafc91SKris Kennaway 			if (fname == NULL || (f = fopen(fname, "r")) == NULL)
709a04a10f8SKris Kennaway 				f = fopen("/etc/motd", "r");
710e8aafc91SKris Kennaway #else /* !LOGIN_CAP */
711e8aafc91SKris Kennaway 			f = fopen("/etc/motd", "r");
712e8aafc91SKris Kennaway #endif /* LOGIN_CAP */
713e8aafc91SKris Kennaway 			/* Print /etc/motd if it exists. */
714a04a10f8SKris Kennaway 			if (f) {
715a04a10f8SKris Kennaway 				while (fgets(line, sizeof(line), f))
716a04a10f8SKris Kennaway 					fputs(line, stdout);
717a04a10f8SKris Kennaway 				fclose(f);
718a04a10f8SKris Kennaway 			}
719a04a10f8SKris Kennaway 		}
720e8aafc91SKris Kennaway #ifdef LOGIN_CAP
721e8aafc91SKris Kennaway 		login_close(lc);
722e8aafc91SKris Kennaway #endif /* LOGIN_CAP */
723e8aafc91SKris Kennaway 
724a04a10f8SKris Kennaway 		/* Do common processing for the child, such as execing the command. */
725db1cb46cSKris Kennaway 		do_child(command, pw, s->term, s->display, s->auth_proto,
726db1cb46cSKris Kennaway 		    s->auth_data, s->tty);
727a04a10f8SKris Kennaway 		/* NOTREACHED */
728a04a10f8SKris Kennaway 	}
729a04a10f8SKris Kennaway 	if (pid < 0)
730a04a10f8SKris Kennaway 		packet_disconnect("fork failed: %.100s", strerror(errno));
731a04a10f8SKris Kennaway 	s->pid = pid;
732a04a10f8SKris Kennaway 
733a04a10f8SKris Kennaway 	/* Parent.  Close the slave side of the pseudo tty. */
734a04a10f8SKris Kennaway 	close(ttyfd);
735a04a10f8SKris Kennaway 
736a04a10f8SKris Kennaway 	/*
737a04a10f8SKris Kennaway 	 * Create another descriptor of the pty master side for use as the
738a04a10f8SKris Kennaway 	 * standard input.  We could use the original descriptor, but this
739a04a10f8SKris Kennaway 	 * simplifies code in server_loop.  The descriptor is bidirectional.
740a04a10f8SKris Kennaway 	 */
741a04a10f8SKris Kennaway 	fdout = dup(ptyfd);
742a04a10f8SKris Kennaway 	if (fdout < 0)
743a04a10f8SKris Kennaway 		packet_disconnect("dup #1 failed: %.100s", strerror(errno));
744a04a10f8SKris Kennaway 
745a04a10f8SKris Kennaway 	/* we keep a reference to the pty master */
746a04a10f8SKris Kennaway 	ptymaster = dup(ptyfd);
747a04a10f8SKris Kennaway 	if (ptymaster < 0)
748a04a10f8SKris Kennaway 		packet_disconnect("dup #2 failed: %.100s", strerror(errno));
749a04a10f8SKris Kennaway 	s->ptymaster = ptymaster;
750a04a10f8SKris Kennaway 
751a04a10f8SKris Kennaway 	/* Enter interactive session. */
752a04a10f8SKris Kennaway 	if (compat20) {
753a04a10f8SKris Kennaway 		session_set_fds(s, ptyfd, fdout, -1);
754a04a10f8SKris Kennaway 	} else {
755a04a10f8SKris Kennaway 		server_loop(pid, ptyfd, fdout, -1);
756a04a10f8SKris Kennaway 		/* server_loop _has_ closed ptyfd and fdout. */
757a04a10f8SKris Kennaway 		session_pty_cleanup(s);
758a04a10f8SKris Kennaway 	}
759a04a10f8SKris Kennaway }
760a04a10f8SKris Kennaway 
761a04a10f8SKris Kennaway /*
762a04a10f8SKris Kennaway  * Sets the value of the given variable in the environment.  If the variable
763a04a10f8SKris Kennaway  * already exists, its value is overriden.
764a04a10f8SKris Kennaway  */
765a04a10f8SKris Kennaway void
766a04a10f8SKris Kennaway child_set_env(char ***envp, unsigned int *envsizep, const char *name,
767a04a10f8SKris Kennaway 	      const char *value)
768a04a10f8SKris Kennaway {
769a04a10f8SKris Kennaway 	unsigned int i, namelen;
770a04a10f8SKris Kennaway 	char **env;
771a04a10f8SKris Kennaway 
772a04a10f8SKris Kennaway 	/*
773a04a10f8SKris Kennaway 	 * Find the slot where the value should be stored.  If the variable
774a04a10f8SKris Kennaway 	 * already exists, we reuse the slot; otherwise we append a new slot
775a04a10f8SKris Kennaway 	 * at the end of the array, expanding if necessary.
776a04a10f8SKris Kennaway 	 */
777a04a10f8SKris Kennaway 	env = *envp;
778a04a10f8SKris Kennaway 	namelen = strlen(name);
779a04a10f8SKris Kennaway 	for (i = 0; env[i]; i++)
780a04a10f8SKris Kennaway 		if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
781a04a10f8SKris Kennaway 			break;
782a04a10f8SKris Kennaway 	if (env[i]) {
783a04a10f8SKris Kennaway 		/* Reuse the slot. */
784a04a10f8SKris Kennaway 		xfree(env[i]);
785a04a10f8SKris Kennaway 	} else {
786a04a10f8SKris Kennaway 		/* New variable.  Expand if necessary. */
787a04a10f8SKris Kennaway 		if (i >= (*envsizep) - 1) {
788a04a10f8SKris Kennaway 			(*envsizep) += 50;
789a04a10f8SKris Kennaway 			env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *));
790a04a10f8SKris Kennaway 		}
791a04a10f8SKris Kennaway 		/* Need to set the NULL pointer at end of array beyond the new slot. */
792a04a10f8SKris Kennaway 		env[i + 1] = NULL;
793a04a10f8SKris Kennaway 	}
794a04a10f8SKris Kennaway 
795a04a10f8SKris Kennaway 	/* Allocate space and format the variable in the appropriate slot. */
796a04a10f8SKris Kennaway 	env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
797a04a10f8SKris Kennaway 	snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
798a04a10f8SKris Kennaway }
799a04a10f8SKris Kennaway 
800a04a10f8SKris Kennaway /*
801a04a10f8SKris Kennaway  * Reads environment variables from the given file and adds/overrides them
802a04a10f8SKris Kennaway  * into the environment.  If the file does not exist, this does nothing.
803a04a10f8SKris Kennaway  * Otherwise, it must consist of empty lines, comments (line starts with '#')
804a04a10f8SKris Kennaway  * and assignments of the form name=value.  No other forms are allowed.
805a04a10f8SKris Kennaway  */
806a04a10f8SKris Kennaway void
807a04a10f8SKris Kennaway read_environment_file(char ***env, unsigned int *envsize,
808a04a10f8SKris Kennaway 		      const char *filename)
809a04a10f8SKris Kennaway {
810a04a10f8SKris Kennaway 	FILE *f;
811a04a10f8SKris Kennaway 	char buf[4096];
812a04a10f8SKris Kennaway 	char *cp, *value;
813a04a10f8SKris Kennaway 
814a04a10f8SKris Kennaway 	f = fopen(filename, "r");
815a04a10f8SKris Kennaway 	if (!f)
816a04a10f8SKris Kennaway 		return;
817a04a10f8SKris Kennaway 
818a04a10f8SKris Kennaway 	while (fgets(buf, sizeof(buf), f)) {
819a04a10f8SKris Kennaway 		for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
820a04a10f8SKris Kennaway 			;
821a04a10f8SKris Kennaway 		if (!*cp || *cp == '#' || *cp == '\n')
822a04a10f8SKris Kennaway 			continue;
823a04a10f8SKris Kennaway 		if (strchr(cp, '\n'))
824a04a10f8SKris Kennaway 			*strchr(cp, '\n') = '\0';
825a04a10f8SKris Kennaway 		value = strchr(cp, '=');
826a04a10f8SKris Kennaway 		if (value == NULL) {
827a04a10f8SKris Kennaway 			fprintf(stderr, "Bad line in %.100s: %.200s\n", filename, buf);
828a04a10f8SKris Kennaway 			continue;
829a04a10f8SKris Kennaway 		}
830db1cb46cSKris Kennaway 		/*
831db1cb46cSKris Kennaway 		 * Replace the equals sign by nul, and advance value to
832db1cb46cSKris Kennaway 		 * the value string.
833db1cb46cSKris Kennaway 		 */
834a04a10f8SKris Kennaway 		*value = '\0';
835a04a10f8SKris Kennaway 		value++;
836a04a10f8SKris Kennaway 		child_set_env(env, envsize, cp, value);
837a04a10f8SKris Kennaway 	}
838a04a10f8SKris Kennaway 	fclose(f);
839a04a10f8SKris Kennaway }
840a04a10f8SKris Kennaway 
841a04a10f8SKris Kennaway /*
842a04a10f8SKris Kennaway  * Performs common processing for the child, such as setting up the
843a04a10f8SKris Kennaway  * environment, closing extra file descriptors, setting the user and group
844a04a10f8SKris Kennaway  * ids, and executing the command or shell.
845a04a10f8SKris Kennaway  */
846a04a10f8SKris Kennaway void
847a04a10f8SKris Kennaway do_child(const char *command, struct passwd * pw, const char *term,
848a04a10f8SKris Kennaway 	 const char *display, const char *auth_proto,
849a04a10f8SKris Kennaway 	 const char *auth_data, const char *ttyname)
850a04a10f8SKris Kennaway {
851e8aafc91SKris Kennaway 	char *shell;
852e8aafc91SKris Kennaway 	const char *cp = NULL;
853a04a10f8SKris Kennaway 	char buf[256];
854a04a10f8SKris Kennaway 	FILE *f;
855a04a10f8SKris Kennaway 	unsigned int envsize, i;
856e8aafc91SKris Kennaway 	char **env = NULL;
857a04a10f8SKris Kennaway 	extern char **environ;
858a04a10f8SKris Kennaway 	struct stat st;
859a04a10f8SKris Kennaway 	char *argv[10];
860a04a10f8SKris Kennaway 
861e8aafc91SKris Kennaway #ifdef LOGIN_CAP
862e8aafc91SKris Kennaway 	login_cap_t *lc;
863e8aafc91SKris Kennaway 
864e8aafc91SKris Kennaway 	lc = login_getpwclass(pw);
865e8aafc91SKris Kennaway 	if (lc == NULL)
866e8aafc91SKris Kennaway 		lc = login_getclassbyname(NULL, pw);
867e8aafc91SKris Kennaway 	if (pw->pw_uid != 0)
868e8aafc91SKris Kennaway 		auth_checknologin(lc);
869e8aafc91SKris Kennaway #else /* !LOGIN_CAP */
870a04a10f8SKris Kennaway 	f = fopen("/etc/nologin", "r");
871a04a10f8SKris Kennaway 	if (f) {
872a04a10f8SKris Kennaway 		/* /etc/nologin exists.  Print its contents and exit. */
873a04a10f8SKris Kennaway 		while (fgets(buf, sizeof(buf), f))
874a04a10f8SKris Kennaway 			fputs(buf, stderr);
875a04a10f8SKris Kennaway 		fclose(f);
876a04a10f8SKris Kennaway 		if (pw->pw_uid != 0)
877a04a10f8SKris Kennaway 			exit(254);
878a04a10f8SKris Kennaway 	}
879e8aafc91SKris Kennaway #endif /* LOGIN_CAP */
880e8aafc91SKris Kennaway 
881e8aafc91SKris Kennaway #ifdef LOGIN_CAP
882e8aafc91SKris Kennaway 	if (options.use_login)
883e8aafc91SKris Kennaway #endif /* LOGIN_CAP */
884a04a10f8SKris Kennaway 	/* Set login name in the kernel. */
885a04a10f8SKris Kennaway 	if (setlogin(pw->pw_name) < 0)
886a04a10f8SKris Kennaway 		error("setlogin failed: %s", strerror(errno));
887a04a10f8SKris Kennaway 
888a04a10f8SKris Kennaway 	/* Set uid, gid, and groups. */
889a04a10f8SKris Kennaway 	/* Login(1) does this as well, and it needs uid 0 for the "-h"
890a04a10f8SKris Kennaway 	   switch, so we let login(1) to this for us. */
891a04a10f8SKris Kennaway 	if (!options.use_login) {
892e8aafc91SKris Kennaway #ifdef LOGIN_CAP
893e8aafc91SKris Kennaway 		char **tmpenv;
894e8aafc91SKris Kennaway 
895e8aafc91SKris Kennaway 		/* Initialize temp environment */
896e8aafc91SKris Kennaway 		envsize = 64;
897e8aafc91SKris Kennaway 		env = xmalloc(envsize * sizeof(char *));
898e8aafc91SKris Kennaway 		env[0] = NULL;
899e8aafc91SKris Kennaway 
900e8aafc91SKris Kennaway 		child_set_env(&env, &envsize, "PATH",
901e8aafc91SKris Kennaway 			      (pw->pw_uid == 0) ?
902e8aafc91SKris Kennaway 			      _PATH_STDPATH : _PATH_DEFPATH);
903e8aafc91SKris Kennaway 
904e8aafc91SKris Kennaway 		snprintf(buf, sizeof buf, "%.200s/%.50s",
905e8aafc91SKris Kennaway 			 _PATH_MAILDIR, pw->pw_name);
906e8aafc91SKris Kennaway 		child_set_env(&env, &envsize, "MAIL", buf);
907e8aafc91SKris Kennaway 
908e8aafc91SKris Kennaway 		if (getenv("TZ"))
909e8aafc91SKris Kennaway 			child_set_env(&env, &envsize, "TZ", getenv("TZ"));
910e8aafc91SKris Kennaway 
911e8aafc91SKris Kennaway 		/* Save parent environment */
912e8aafc91SKris Kennaway 		tmpenv = environ;
913e8aafc91SKris Kennaway 		environ = env;
914e8aafc91SKris Kennaway 
915e8aafc91SKris Kennaway 		if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETALL) < 0)
916e8aafc91SKris Kennaway 			fatal("setusercontext failed: %s", strerror(errno));
917e8aafc91SKris Kennaway 
918e8aafc91SKris Kennaway 		/* Restore parent environment */
919e8aafc91SKris Kennaway 		env = environ;
920e8aafc91SKris Kennaway 		environ = tmpenv;
921e8aafc91SKris Kennaway 
922e8aafc91SKris Kennaway 		for (envsize = 0; env[envsize] != NULL; ++envsize)
923e8aafc91SKris Kennaway 			;
924e8aafc91SKris Kennaway 		envsize = (envsize < 100) ? 100 : envsize + 16;
925e8aafc91SKris Kennaway 		env = xrealloc(env, envsize * sizeof(char *));
926e8aafc91SKris Kennaway 
927e8aafc91SKris Kennaway #else /* !LOGIN_CAP */
928a04a10f8SKris Kennaway 		if (getuid() == 0 || geteuid() == 0) {
929a04a10f8SKris Kennaway 			if (setgid(pw->pw_gid) < 0) {
930a04a10f8SKris Kennaway 				perror("setgid");
931a04a10f8SKris Kennaway 				exit(1);
932a04a10f8SKris Kennaway 			}
933a04a10f8SKris Kennaway 			/* Initialize the group list. */
934a04a10f8SKris Kennaway 			if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
935a04a10f8SKris Kennaway 				perror("initgroups");
936a04a10f8SKris Kennaway 				exit(1);
937a04a10f8SKris Kennaway 			}
938a04a10f8SKris Kennaway 			endgrent();
939a04a10f8SKris Kennaway 
940a04a10f8SKris Kennaway 			/* Permanently switch to the desired uid. */
941a04a10f8SKris Kennaway 			permanently_set_uid(pw->pw_uid);
942a04a10f8SKris Kennaway 		}
943a04a10f8SKris Kennaway 		if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
944a04a10f8SKris Kennaway 			fatal("Failed to set uids to %d.", (int) pw->pw_uid);
945e8aafc91SKris Kennaway #endif /* LOGIN_CAP */
946a04a10f8SKris Kennaway 	}
947a04a10f8SKris Kennaway 	/*
948a04a10f8SKris Kennaway 	 * Get the shell from the password data.  An empty shell field is
949a04a10f8SKris Kennaway 	 * legal, and means /bin/sh.
950a04a10f8SKris Kennaway 	 */
951a04a10f8SKris Kennaway 	shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
952e8aafc91SKris Kennaway #ifdef LOGIN_CAP
953e8aafc91SKris Kennaway 	shell = login_getcapstr(lc, "shell", shell, shell);
954e8aafc91SKris Kennaway #endif /* LOGIN_CAP */
955a04a10f8SKris Kennaway 
956a04a10f8SKris Kennaway #ifdef AFS
957a04a10f8SKris Kennaway 	/* Try to get AFS tokens for the local cell. */
958a04a10f8SKris Kennaway 	if (k_hasafs()) {
959a04a10f8SKris Kennaway 		char cell[64];
960a04a10f8SKris Kennaway 
961a04a10f8SKris Kennaway 		if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
962a04a10f8SKris Kennaway 			krb_afslog(cell, 0);
963a04a10f8SKris Kennaway 
964a04a10f8SKris Kennaway 		krb_afslog(0, 0);
965a04a10f8SKris Kennaway 	}
966a04a10f8SKris Kennaway #endif /* AFS */
967a04a10f8SKris Kennaway 
968a04a10f8SKris Kennaway 	/* Initialize the environment. */
969e8aafc91SKris Kennaway 	if (env == NULL) {
970a04a10f8SKris Kennaway 		envsize = 100;
971a04a10f8SKris Kennaway 		env = xmalloc(envsize * sizeof(char *));
972a04a10f8SKris Kennaway 		env[0] = NULL;
973e8aafc91SKris Kennaway 	}
974a04a10f8SKris Kennaway 
975a04a10f8SKris Kennaway 	if (!options.use_login) {
976a04a10f8SKris Kennaway 		/* Set basic environment. */
977a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, "USER", pw->pw_name);
978a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
979a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, "HOME", pw->pw_dir);
980e8aafc91SKris Kennaway #ifndef LOGIN_CAP
981a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
982a04a10f8SKris Kennaway 
983a04a10f8SKris Kennaway 		snprintf(buf, sizeof buf, "%.200s/%.50s",
984a04a10f8SKris Kennaway 			 _PATH_MAILDIR, pw->pw_name);
985a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, "MAIL", buf);
986e8aafc91SKris Kennaway #endif /* !LOGIN_CAP */
987a04a10f8SKris Kennaway 
988a04a10f8SKris Kennaway 		/* Normal systems set SHELL by default. */
989a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, "SHELL", shell);
990a04a10f8SKris Kennaway 	}
991e8aafc91SKris Kennaway #ifdef LOGIN_CAP
992e8aafc91SKris Kennaway 	if (options.use_login)
993e8aafc91SKris Kennaway #endif /* LOGIN_CAP */
994a04a10f8SKris Kennaway 	if (getenv("TZ"))
995a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, "TZ", getenv("TZ"));
996a04a10f8SKris Kennaway 
997a04a10f8SKris Kennaway 	/* Set custom environment options from RSA authentication. */
998a04a10f8SKris Kennaway 	while (custom_environment) {
999a04a10f8SKris Kennaway 		struct envstring *ce = custom_environment;
1000a04a10f8SKris Kennaway 		char *s = ce->s;
1001a04a10f8SKris Kennaway 		int i;
1002a04a10f8SKris Kennaway 		for (i = 0; s[i] != '=' && s[i]; i++);
1003a04a10f8SKris Kennaway 		if (s[i] == '=') {
1004a04a10f8SKris Kennaway 			s[i] = 0;
1005a04a10f8SKris Kennaway 			child_set_env(&env, &envsize, s, s + i + 1);
1006a04a10f8SKris Kennaway 		}
1007a04a10f8SKris Kennaway 		custom_environment = ce->next;
1008a04a10f8SKris Kennaway 		xfree(ce->s);
1009a04a10f8SKris Kennaway 		xfree(ce);
1010a04a10f8SKris Kennaway 	}
1011a04a10f8SKris Kennaway 
1012a04a10f8SKris Kennaway 	snprintf(buf, sizeof buf, "%.50s %d %d",
1013a04a10f8SKris Kennaway 		 get_remote_ipaddr(), get_remote_port(), get_local_port());
1014a04a10f8SKris Kennaway 	child_set_env(&env, &envsize, "SSH_CLIENT", buf);
1015a04a10f8SKris Kennaway 
1016a04a10f8SKris Kennaway 	if (ttyname)
1017a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, "SSH_TTY", ttyname);
1018a04a10f8SKris Kennaway 	if (term)
1019a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, "TERM", term);
1020a04a10f8SKris Kennaway 	if (display)
1021a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, "DISPLAY", display);
1022a04a10f8SKris Kennaway 
1023a04a10f8SKris Kennaway #ifdef KRB4
1024a04a10f8SKris Kennaway 	{
1025a04a10f8SKris Kennaway 		extern char *ticket;
1026a04a10f8SKris Kennaway 
1027a04a10f8SKris Kennaway 		if (ticket)
1028a04a10f8SKris Kennaway 			child_set_env(&env, &envsize, "KRBTKFILE", ticket);
1029a04a10f8SKris Kennaway 	}
1030a04a10f8SKris Kennaway #endif /* KRB4 */
1031e8aafc91SKris Kennaway #ifdef KRB5
1032e8aafc91SKris Kennaway {
1033e8aafc91SKris Kennaway 	  extern krb5_ccache mem_ccache;
1034e8aafc91SKris Kennaway 
1035e8aafc91SKris Kennaway 	   if (mem_ccache) {
1036e8aafc91SKris Kennaway 	     krb5_error_code problem;
1037e8aafc91SKris Kennaway 	      krb5_ccache ccache;
1038e8aafc91SKris Kennaway #ifdef AFS
1039e8aafc91SKris Kennaway 	      if (k_hasafs())
1040e8aafc91SKris Kennaway 		krb5_afslog(ssh_context, mem_ccache, NULL, NULL);
1041e8aafc91SKris Kennaway #endif /* AFS */
1042e8aafc91SKris Kennaway 
1043e8aafc91SKris Kennaway 	      problem = krb5_cc_default(ssh_context, &ccache);
1044e8aafc91SKris Kennaway 	      if (problem) {}
1045e8aafc91SKris Kennaway 	      else {
1046e8aafc91SKris Kennaway 		problem = krb5_cc_copy_cache(ssh_context, mem_ccache, ccache);
1047e8aafc91SKris Kennaway 		 if (problem) {}
1048e8aafc91SKris Kennaway 	      }
1049e8aafc91SKris Kennaway 
1050e8aafc91SKris Kennaway 	      krb5_cc_close(ssh_context, ccache);
1051e8aafc91SKris Kennaway 	   }
1052e8aafc91SKris Kennaway 
1053e8aafc91SKris Kennaway 	   krb5_cleanup_proc(NULL);
1054e8aafc91SKris Kennaway 	}
1055e8aafc91SKris Kennaway #endif /* KRB5 */
1056a04a10f8SKris Kennaway 
1057a04a10f8SKris Kennaway 	if (xauthfile)
1058a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, "XAUTHORITY", xauthfile);
1059a04a10f8SKris Kennaway 	if (auth_get_socket_name() != NULL)
1060a04a10f8SKris Kennaway 		child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
1061a04a10f8SKris Kennaway 			      auth_get_socket_name());
1062a04a10f8SKris Kennaway 
1063a04a10f8SKris Kennaway 	/* read $HOME/.ssh/environment. */
1064a04a10f8SKris Kennaway 	if (!options.use_login) {
1065db1cb46cSKris Kennaway 		snprintf(buf, sizeof buf, "%.200s/.ssh/environment",
1066db1cb46cSKris Kennaway 		    pw->pw_dir);
1067a04a10f8SKris Kennaway 		read_environment_file(&env, &envsize, buf);
1068a04a10f8SKris Kennaway 	}
1069a04a10f8SKris Kennaway 	if (debug_flag) {
1070a04a10f8SKris Kennaway 		/* dump the environment */
1071a04a10f8SKris Kennaway 		fprintf(stderr, "Environment:\n");
1072a04a10f8SKris Kennaway 		for (i = 0; env[i]; i++)
1073a04a10f8SKris Kennaway 			fprintf(stderr, "  %.200s\n", env[i]);
1074a04a10f8SKris Kennaway 	}
1075a04a10f8SKris Kennaway 	/*
1076a04a10f8SKris Kennaway 	 * Close the connection descriptors; note that this is the child, and
1077a04a10f8SKris Kennaway 	 * the server will still have the socket open, and it is important
1078a04a10f8SKris Kennaway 	 * that we do not shutdown it.  Note that the descriptors cannot be
1079a04a10f8SKris Kennaway 	 * closed before building the environment, as we call
1080a04a10f8SKris Kennaway 	 * get_remote_ipaddr there.
1081a04a10f8SKris Kennaway 	 */
1082a04a10f8SKris Kennaway 	if (packet_get_connection_in() == packet_get_connection_out())
1083a04a10f8SKris Kennaway 		close(packet_get_connection_in());
1084a04a10f8SKris Kennaway 	else {
1085a04a10f8SKris Kennaway 		close(packet_get_connection_in());
1086a04a10f8SKris Kennaway 		close(packet_get_connection_out());
1087a04a10f8SKris Kennaway 	}
1088a04a10f8SKris Kennaway 	/*
1089a04a10f8SKris Kennaway 	 * Close all descriptors related to channels.  They will still remain
1090a04a10f8SKris Kennaway 	 * open in the parent.
1091a04a10f8SKris Kennaway 	 */
1092a04a10f8SKris Kennaway 	/* XXX better use close-on-exec? -markus */
1093a04a10f8SKris Kennaway 	channel_close_all();
1094a04a10f8SKris Kennaway 
1095a04a10f8SKris Kennaway 	/*
1096a04a10f8SKris Kennaway 	 * Close any extra file descriptors.  Note that there may still be
1097a04a10f8SKris Kennaway 	 * descriptors left by system functions.  They will be closed later.
1098a04a10f8SKris Kennaway 	 */
1099a04a10f8SKris Kennaway 	endpwent();
1100a04a10f8SKris Kennaway 
1101a04a10f8SKris Kennaway 	/*
1102a04a10f8SKris Kennaway 	 * Close any extra open file descriptors so that we don\'t have them
1103a04a10f8SKris Kennaway 	 * hanging around in clients.  Note that we want to do this after
1104a04a10f8SKris Kennaway 	 * initgroups, because at least on Solaris 2.3 it leaves file
1105a04a10f8SKris Kennaway 	 * descriptors open.
1106a04a10f8SKris Kennaway 	 */
1107e8aafc91SKris Kennaway 	for (i = 3; i < getdtablesize(); i++)
1108a04a10f8SKris Kennaway 		close(i);
1109a04a10f8SKris Kennaway 
1110a04a10f8SKris Kennaway 	/* Change current directory to the user\'s home directory. */
1111e8aafc91SKris Kennaway 	if (
1112e8aafc91SKris Kennaway #ifdef __FreeBSD__
1113e8aafc91SKris Kennaway 		!*pw->pw_dir ||
1114e8aafc91SKris Kennaway #endif /* __FreeBSD__ */
1115e8aafc91SKris Kennaway 		chdir(pw->pw_dir) < 0
1116e8aafc91SKris Kennaway 	   ) {
1117e8aafc91SKris Kennaway #ifdef __FreeBSD__
1118e8aafc91SKris Kennaway 		int quiet_login = 0;
1119e8aafc91SKris Kennaway #endif /* __FreeBSD__ */
1120e8aafc91SKris Kennaway #ifdef LOGIN_CAP
1121e8aafc91SKris Kennaway 		if (login_getcapbool(lc, "requirehome", 0)) {
1122e8aafc91SKris Kennaway 			(void)printf("Home directory not available\n");
1123e8aafc91SKris Kennaway 			log("LOGIN %.200s REFUSED (HOMEDIR) ON TTY %.200s",
1124e8aafc91SKris Kennaway 				pw->pw_name, ttyname);
1125e8aafc91SKris Kennaway 			exit(254);
1126e8aafc91SKris Kennaway 		}
1127e8aafc91SKris Kennaway #endif /* LOGIN_CAP */
1128e8aafc91SKris Kennaway #ifdef __FreeBSD__
1129e8aafc91SKris Kennaway 		if (chdir("/") < 0) {
1130e8aafc91SKris Kennaway 			(void)printf("Cannot find root directory\n");
1131e8aafc91SKris Kennaway 			log("LOGIN %.200s REFUSED (ROOTDIR) ON TTY %.200s",
1132e8aafc91SKris Kennaway 				pw->pw_name, ttyname);
1133e8aafc91SKris Kennaway 			exit(254);
1134e8aafc91SKris Kennaway 		}
1135e8aafc91SKris Kennaway #ifdef LOGIN_CAP
1136e8aafc91SKris Kennaway 		quiet_login = login_getcapbool(lc, "hushlogin", 0);
1137e8aafc91SKris Kennaway #endif /* LOGIN_CAP */
1138e8aafc91SKris Kennaway 		if (!quiet_login || *pw->pw_dir)
1139e8aafc91SKris Kennaway 			(void)printf(
1140e8aafc91SKris Kennaway 		       "No home directory.\nLogging in with home = \"/\".\n");
1141e8aafc91SKris Kennaway 
1142e8aafc91SKris Kennaway #else /* !__FreeBSD__ */
1143e8aafc91SKris Kennaway 
1144a04a10f8SKris Kennaway 		fprintf(stderr, "Could not chdir to home directory %s: %s\n",
1145a04a10f8SKris Kennaway 			pw->pw_dir, strerror(errno));
1146e8aafc91SKris Kennaway #endif /* __FreeBSD__ */
1147e8aafc91SKris Kennaway 	}
1148e8aafc91SKris Kennaway #ifdef LOGIN_CAP
1149e8aafc91SKris Kennaway 	login_close(lc);
1150e8aafc91SKris Kennaway #endif /* LOGIN_CAP */
1151a04a10f8SKris Kennaway 
1152a04a10f8SKris Kennaway 	/*
1153a04a10f8SKris Kennaway 	 * Must take new environment into use so that .ssh/rc, /etc/sshrc and
1154a04a10f8SKris Kennaway 	 * xauth are run in the proper environment.
1155a04a10f8SKris Kennaway 	 */
1156a04a10f8SKris Kennaway 	environ = env;
1157a04a10f8SKris Kennaway 
1158a04a10f8SKris Kennaway 	/*
1159a04a10f8SKris Kennaway 	 * Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first
1160a04a10f8SKris Kennaway 	 * in this order).
1161a04a10f8SKris Kennaway 	 */
1162a04a10f8SKris Kennaway 	if (!options.use_login) {
1163a04a10f8SKris Kennaway 		if (stat(SSH_USER_RC, &st) >= 0) {
1164a04a10f8SKris Kennaway 			if (debug_flag)
1165a04a10f8SKris Kennaway 				fprintf(stderr, "Running /bin/sh %s\n", SSH_USER_RC);
1166a04a10f8SKris Kennaway 
1167a04a10f8SKris Kennaway 			f = popen("/bin/sh " SSH_USER_RC, "w");
1168a04a10f8SKris Kennaway 			if (f) {
1169a04a10f8SKris Kennaway 				if (auth_proto != NULL && auth_data != NULL)
1170a04a10f8SKris Kennaway 					fprintf(f, "%s %s\n", auth_proto, auth_data);
1171a04a10f8SKris Kennaway 				pclose(f);
1172a04a10f8SKris Kennaway 			} else
1173a04a10f8SKris Kennaway 				fprintf(stderr, "Could not run %s\n", SSH_USER_RC);
1174a04a10f8SKris Kennaway 		} else if (stat(SSH_SYSTEM_RC, &st) >= 0) {
1175a04a10f8SKris Kennaway 			if (debug_flag)
1176a04a10f8SKris Kennaway 				fprintf(stderr, "Running /bin/sh %s\n", SSH_SYSTEM_RC);
1177a04a10f8SKris Kennaway 
1178a04a10f8SKris Kennaway 			f = popen("/bin/sh " SSH_SYSTEM_RC, "w");
1179a04a10f8SKris Kennaway 			if (f) {
1180a04a10f8SKris Kennaway 				if (auth_proto != NULL && auth_data != NULL)
1181a04a10f8SKris Kennaway 					fprintf(f, "%s %s\n", auth_proto, auth_data);
1182a04a10f8SKris Kennaway 				pclose(f);
1183a04a10f8SKris Kennaway 			} else
1184a04a10f8SKris Kennaway 				fprintf(stderr, "Could not run %s\n", SSH_SYSTEM_RC);
1185a04a10f8SKris Kennaway 		}
1186a04a10f8SKris Kennaway #ifdef XAUTH_PATH
1187a04a10f8SKris Kennaway 		else {
1188a04a10f8SKris Kennaway 			/* Add authority data to .Xauthority if appropriate. */
1189a04a10f8SKris Kennaway 			if (auth_proto != NULL && auth_data != NULL) {
1190db1cb46cSKris Kennaway 				char *screen = strchr(display, ':');
1191db1cb46cSKris Kennaway 				if (debug_flag) {
1192db1cb46cSKris Kennaway 					fprintf(stderr,
1193db1cb46cSKris Kennaway 					    "Running %.100s add %.100s %.100s %.100s\n",
1194a04a10f8SKris Kennaway 					    XAUTH_PATH, display, auth_proto, auth_data);
1195db1cb46cSKris Kennaway 					if (screen != NULL)
1196db1cb46cSKris Kennaway 						fprintf(stderr,
1197db1cb46cSKris Kennaway 						    "Adding %.*s/unix%s %s %s\n",
1198db1cb46cSKris Kennaway 						    screen-display, display,
1199db1cb46cSKris Kennaway 						    screen, auth_proto, auth_data);
1200db1cb46cSKris Kennaway 				}
1201a04a10f8SKris Kennaway 				f = popen(XAUTH_PATH " -q -", "w");
1202a04a10f8SKris Kennaway 				if (f) {
1203db1cb46cSKris Kennaway 					fprintf(f, "add %s %s %s\n", display,
1204db1cb46cSKris Kennaway 					    auth_proto, auth_data);
1205db1cb46cSKris Kennaway 					if (screen != NULL)
1206db1cb46cSKris Kennaway 						fprintf(f, "add %.*s/unix%s %s %s\n",
1207db1cb46cSKris Kennaway 						    screen-display, display,
1208db1cb46cSKris Kennaway 						    screen, auth_proto, auth_data);
1209a04a10f8SKris Kennaway 					pclose(f);
1210a04a10f8SKris Kennaway 				} else
1211db1cb46cSKris Kennaway 					fprintf(stderr, "Could not run %s -q -\n",
1212db1cb46cSKris Kennaway 					    XAUTH_PATH);
1213a04a10f8SKris Kennaway 			}
1214a04a10f8SKris Kennaway 		}
1215a04a10f8SKris Kennaway #endif /* XAUTH_PATH */
1216a04a10f8SKris Kennaway 
1217a04a10f8SKris Kennaway 		/* Get the last component of the shell name. */
1218a04a10f8SKris Kennaway 		cp = strrchr(shell, '/');
1219a04a10f8SKris Kennaway 		if (cp)
1220a04a10f8SKris Kennaway 			cp++;
1221a04a10f8SKris Kennaway 		else
1222a04a10f8SKris Kennaway 			cp = shell;
1223a04a10f8SKris Kennaway 	}
1224a04a10f8SKris Kennaway 	/*
1225a04a10f8SKris Kennaway 	 * If we have no command, execute the shell.  In this case, the shell
1226a04a10f8SKris Kennaway 	 * name to be passed in argv[0] is preceded by '-' to indicate that
1227a04a10f8SKris Kennaway 	 * this is a login shell.
1228a04a10f8SKris Kennaway 	 */
1229a04a10f8SKris Kennaway 	if (!command) {
1230a04a10f8SKris Kennaway 		if (!options.use_login) {
1231a04a10f8SKris Kennaway 			char buf[256];
1232a04a10f8SKris Kennaway 
1233a04a10f8SKris Kennaway 			/*
1234a04a10f8SKris Kennaway 			 * Check for mail if we have a tty and it was enabled
1235a04a10f8SKris Kennaway 			 * in server options.
1236a04a10f8SKris Kennaway 			 */
1237a04a10f8SKris Kennaway 			if (ttyname && options.check_mail) {
1238a04a10f8SKris Kennaway 				char *mailbox;
1239a04a10f8SKris Kennaway 				struct stat mailstat;
1240a04a10f8SKris Kennaway 				mailbox = getenv("MAIL");
1241a04a10f8SKris Kennaway 				if (mailbox != NULL) {
1242db1cb46cSKris Kennaway 					if (stat(mailbox, &mailstat) != 0 ||
1243db1cb46cSKris Kennaway 					    mailstat.st_size == 0)
1244e8aafc91SKris Kennaway #ifdef __FreeBSD__
1245e8aafc91SKris Kennaway 						;
1246e8aafc91SKris Kennaway #else /* !__FreeBSD__ */
1247a04a10f8SKris Kennaway 						printf("No mail.\n");
1248e8aafc91SKris Kennaway #endif /* __FreeBSD__ */
1249a04a10f8SKris Kennaway 					else if (mailstat.st_mtime < mailstat.st_atime)
1250a04a10f8SKris Kennaway 						printf("You have mail.\n");
1251a04a10f8SKris Kennaway 					else
1252a04a10f8SKris Kennaway 						printf("You have new mail.\n");
1253a04a10f8SKris Kennaway 				}
1254a04a10f8SKris Kennaway 			}
1255a04a10f8SKris Kennaway 			/* Start the shell.  Set initial character to '-'. */
1256a04a10f8SKris Kennaway 			buf[0] = '-';
1257a04a10f8SKris Kennaway 			strncpy(buf + 1, cp, sizeof(buf) - 1);
1258a04a10f8SKris Kennaway 			buf[sizeof(buf) - 1] = 0;
1259a04a10f8SKris Kennaway 
1260a04a10f8SKris Kennaway 			/* Execute the shell. */
1261a04a10f8SKris Kennaway 			argv[0] = buf;
1262a04a10f8SKris Kennaway 			argv[1] = NULL;
1263a04a10f8SKris Kennaway 			execve(shell, argv, env);
1264a04a10f8SKris Kennaway 
1265a04a10f8SKris Kennaway 			/* Executing the shell failed. */
1266a04a10f8SKris Kennaway 			perror(shell);
1267a04a10f8SKris Kennaway 			exit(1);
1268a04a10f8SKris Kennaway 
1269a04a10f8SKris Kennaway 		} else {
1270a04a10f8SKris Kennaway 			/* Launch login(1). */
1271a04a10f8SKris Kennaway 
1272a04a10f8SKris Kennaway 			execl("/usr/bin/login", "login", "-h", get_remote_ipaddr(),
1273a04a10f8SKris Kennaway 			      "-p", "-f", "--", pw->pw_name, NULL);
1274a04a10f8SKris Kennaway 
1275a04a10f8SKris Kennaway 			/* Login couldn't be executed, die. */
1276a04a10f8SKris Kennaway 
1277a04a10f8SKris Kennaway 			perror("login");
1278a04a10f8SKris Kennaway 			exit(1);
1279a04a10f8SKris Kennaway 		}
1280a04a10f8SKris Kennaway 	}
1281a04a10f8SKris Kennaway 	/*
1282a04a10f8SKris Kennaway 	 * Execute the command using the user's shell.  This uses the -c
1283a04a10f8SKris Kennaway 	 * option to execute the command.
1284a04a10f8SKris Kennaway 	 */
1285a04a10f8SKris Kennaway 	argv[0] = (char *) cp;
1286a04a10f8SKris Kennaway 	argv[1] = "-c";
1287a04a10f8SKris Kennaway 	argv[2] = (char *) command;
1288a04a10f8SKris Kennaway 	argv[3] = NULL;
1289a04a10f8SKris Kennaway 	execve(shell, argv, env);
1290a04a10f8SKris Kennaway 	perror(shell);
1291a04a10f8SKris Kennaway 	exit(1);
1292a04a10f8SKris Kennaway }
1293a04a10f8SKris Kennaway 
1294a04a10f8SKris Kennaway Session *
1295a04a10f8SKris Kennaway session_new(void)
1296a04a10f8SKris Kennaway {
1297a04a10f8SKris Kennaway 	int i;
1298a04a10f8SKris Kennaway 	static int did_init = 0;
1299a04a10f8SKris Kennaway 	if (!did_init) {
1300a04a10f8SKris Kennaway 		debug("session_new: init");
1301a04a10f8SKris Kennaway 		for(i = 0; i < MAX_SESSIONS; i++) {
1302a04a10f8SKris Kennaway 			sessions[i].used = 0;
1303a04a10f8SKris Kennaway 			sessions[i].self = i;
1304a04a10f8SKris Kennaway 		}
1305a04a10f8SKris Kennaway 		did_init = 1;
1306a04a10f8SKris Kennaway 	}
1307a04a10f8SKris Kennaway 	for(i = 0; i < MAX_SESSIONS; i++) {
1308a04a10f8SKris Kennaway 		Session *s = &sessions[i];
1309a04a10f8SKris Kennaway 		if (! s->used) {
1310a04a10f8SKris Kennaway 			s->pid = 0;
1311a04a10f8SKris Kennaway 			s->extended = 0;
1312a04a10f8SKris Kennaway 			s->chanid = -1;
1313a04a10f8SKris Kennaway 			s->ptyfd = -1;
1314a04a10f8SKris Kennaway 			s->ttyfd = -1;
1315a04a10f8SKris Kennaway 			s->term = NULL;
1316a04a10f8SKris Kennaway 			s->pw = NULL;
1317a04a10f8SKris Kennaway 			s->display = NULL;
1318a04a10f8SKris Kennaway 			s->screen = 0;
1319a04a10f8SKris Kennaway 			s->auth_data = NULL;
1320a04a10f8SKris Kennaway 			s->auth_proto = NULL;
1321a04a10f8SKris Kennaway 			s->used = 1;
1322a04a10f8SKris Kennaway 			s->pw = NULL;
1323a04a10f8SKris Kennaway 			debug("session_new: session %d", i);
1324a04a10f8SKris Kennaway 			return s;
1325a04a10f8SKris Kennaway 		}
1326a04a10f8SKris Kennaway 	}
1327a04a10f8SKris Kennaway 	return NULL;
1328a04a10f8SKris Kennaway }
1329a04a10f8SKris Kennaway 
1330a04a10f8SKris Kennaway void
1331a04a10f8SKris Kennaway session_dump(void)
1332a04a10f8SKris Kennaway {
1333a04a10f8SKris Kennaway 	int i;
1334a04a10f8SKris Kennaway 	for(i = 0; i < MAX_SESSIONS; i++) {
1335a04a10f8SKris Kennaway 		Session *s = &sessions[i];
1336a04a10f8SKris Kennaway 		debug("dump: used %d session %d %p channel %d pid %d",
1337a04a10f8SKris Kennaway 		    s->used,
1338a04a10f8SKris Kennaway 		    s->self,
1339a04a10f8SKris Kennaway 		    s,
1340a04a10f8SKris Kennaway 		    s->chanid,
1341a04a10f8SKris Kennaway 		    s->pid);
1342a04a10f8SKris Kennaway 	}
1343a04a10f8SKris Kennaway }
1344a04a10f8SKris Kennaway 
1345a04a10f8SKris Kennaway int
1346a04a10f8SKris Kennaway session_open(int chanid)
1347a04a10f8SKris Kennaway {
1348a04a10f8SKris Kennaway 	Session *s = session_new();
1349a04a10f8SKris Kennaway 	debug("session_open: channel %d", chanid);
1350a04a10f8SKris Kennaway 	if (s == NULL) {
1351a04a10f8SKris Kennaway 		error("no more sessions");
1352a04a10f8SKris Kennaway 		return 0;
1353a04a10f8SKris Kennaway 	}
1354a04a10f8SKris Kennaway 	s->pw = auth_get_user();
1355a04a10f8SKris Kennaway 	if (s->pw == NULL)
1356a04a10f8SKris Kennaway 		fatal("no user for session %i", s->self);
1357a04a10f8SKris Kennaway 	debug("session_open: session %d: link with channel %d", s->self, chanid);
1358a04a10f8SKris Kennaway 	s->chanid = chanid;
1359a04a10f8SKris Kennaway 	return 1;
1360a04a10f8SKris Kennaway }
1361a04a10f8SKris Kennaway 
1362a04a10f8SKris Kennaway Session *
1363a04a10f8SKris Kennaway session_by_channel(int id)
1364a04a10f8SKris Kennaway {
1365a04a10f8SKris Kennaway 	int i;
1366a04a10f8SKris Kennaway 	for(i = 0; i < MAX_SESSIONS; i++) {
1367a04a10f8SKris Kennaway 		Session *s = &sessions[i];
1368a04a10f8SKris Kennaway 		if (s->used && s->chanid == id) {
1369a04a10f8SKris Kennaway 			debug("session_by_channel: session %d channel %d", i, id);
1370a04a10f8SKris Kennaway 			return s;
1371a04a10f8SKris Kennaway 		}
1372a04a10f8SKris Kennaway 	}
1373a04a10f8SKris Kennaway 	debug("session_by_channel: unknown channel %d", id);
1374a04a10f8SKris Kennaway 	session_dump();
1375a04a10f8SKris Kennaway 	return NULL;
1376a04a10f8SKris Kennaway }
1377a04a10f8SKris Kennaway 
1378a04a10f8SKris Kennaway Session *
1379a04a10f8SKris Kennaway session_by_pid(pid_t pid)
1380a04a10f8SKris Kennaway {
1381a04a10f8SKris Kennaway 	int i;
1382a04a10f8SKris Kennaway 	debug("session_by_pid: pid %d", pid);
1383a04a10f8SKris Kennaway 	for(i = 0; i < MAX_SESSIONS; i++) {
1384a04a10f8SKris Kennaway 		Session *s = &sessions[i];
1385a04a10f8SKris Kennaway 		if (s->used && s->pid == pid)
1386a04a10f8SKris Kennaway 			return s;
1387a04a10f8SKris Kennaway 	}
1388a04a10f8SKris Kennaway 	error("session_by_pid: unknown pid %d", pid);
1389a04a10f8SKris Kennaway 	session_dump();
1390a04a10f8SKris Kennaway 	return NULL;
1391a04a10f8SKris Kennaway }
1392a04a10f8SKris Kennaway 
1393a04a10f8SKris Kennaway int
1394a04a10f8SKris Kennaway session_window_change_req(Session *s)
1395a04a10f8SKris Kennaway {
1396a04a10f8SKris Kennaway 	s->col = packet_get_int();
1397a04a10f8SKris Kennaway 	s->row = packet_get_int();
1398a04a10f8SKris Kennaway 	s->xpixel = packet_get_int();
1399a04a10f8SKris Kennaway 	s->ypixel = packet_get_int();
1400a04a10f8SKris Kennaway 	packet_done();
1401a04a10f8SKris Kennaway 	pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
1402a04a10f8SKris Kennaway 	return 1;
1403a04a10f8SKris Kennaway }
1404a04a10f8SKris Kennaway 
1405a04a10f8SKris Kennaway int
1406a04a10f8SKris Kennaway session_pty_req(Session *s)
1407a04a10f8SKris Kennaway {
1408a04a10f8SKris Kennaway 	unsigned int len;
1409a04a10f8SKris Kennaway 	char *term_modes;	/* encoded terminal modes */
1410a04a10f8SKris Kennaway 
1411a04a10f8SKris Kennaway 	if (s->ttyfd != -1)
1412a04a10f8SKris Kennaway 		return 0;
1413a04a10f8SKris Kennaway 	s->term = packet_get_string(&len);
1414a04a10f8SKris Kennaway 	s->col = packet_get_int();
1415a04a10f8SKris Kennaway 	s->row = packet_get_int();
1416a04a10f8SKris Kennaway 	s->xpixel = packet_get_int();
1417a04a10f8SKris Kennaway 	s->ypixel = packet_get_int();
1418a04a10f8SKris Kennaway 	term_modes = packet_get_string(&len);
1419a04a10f8SKris Kennaway 	packet_done();
1420a04a10f8SKris Kennaway 
1421a04a10f8SKris Kennaway 	if (strcmp(s->term, "") == 0) {
1422a04a10f8SKris Kennaway 		xfree(s->term);
1423a04a10f8SKris Kennaway 		s->term = NULL;
1424a04a10f8SKris Kennaway 	}
1425a04a10f8SKris Kennaway 	/* Allocate a pty and open it. */
1426a04a10f8SKris Kennaway 	if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) {
1427a04a10f8SKris Kennaway 		xfree(s->term);
1428a04a10f8SKris Kennaway 		s->term = NULL;
1429a04a10f8SKris Kennaway 		s->ptyfd = -1;
1430a04a10f8SKris Kennaway 		s->ttyfd = -1;
1431a04a10f8SKris Kennaway 		error("session_pty_req: session %d alloc failed", s->self);
1432a04a10f8SKris Kennaway 		xfree(term_modes);
1433a04a10f8SKris Kennaway 		return 0;
1434a04a10f8SKris Kennaway 	}
1435a04a10f8SKris Kennaway 	debug("session_pty_req: session %d alloc %s", s->self, s->tty);
1436a04a10f8SKris Kennaway 	/*
1437a04a10f8SKris Kennaway 	 * Add a cleanup function to clear the utmp entry and record logout
1438a04a10f8SKris Kennaway 	 * time in case we call fatal() (e.g., the connection gets closed).
1439a04a10f8SKris Kennaway 	 */
1440a04a10f8SKris Kennaway 	fatal_add_cleanup(pty_cleanup_proc, (void *)s);
1441a04a10f8SKris Kennaway 	pty_setowner(s->pw, s->tty);
1442a04a10f8SKris Kennaway 	/* Get window size from the packet. */
1443a04a10f8SKris Kennaway 	pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
1444a04a10f8SKris Kennaway 
1445a04a10f8SKris Kennaway 	session_proctitle(s);
1446a04a10f8SKris Kennaway 
1447a04a10f8SKris Kennaway 	/* XXX parse and set terminal modes */
1448a04a10f8SKris Kennaway 	xfree(term_modes);
1449a04a10f8SKris Kennaway 	return 1;
1450a04a10f8SKris Kennaway }
1451a04a10f8SKris Kennaway 
1452a04a10f8SKris Kennaway int
1453a04a10f8SKris Kennaway session_subsystem_req(Session *s)
1454a04a10f8SKris Kennaway {
1455a04a10f8SKris Kennaway 	unsigned int len;
1456a04a10f8SKris Kennaway 	int success = 0;
1457a04a10f8SKris Kennaway 	char *subsys = packet_get_string(&len);
1458a04a10f8SKris Kennaway 
1459a04a10f8SKris Kennaway 	packet_done();
1460a04a10f8SKris Kennaway 	log("subsystem request for %s", subsys);
1461a04a10f8SKris Kennaway 
1462a04a10f8SKris Kennaway 	xfree(subsys);
1463a04a10f8SKris Kennaway 	return success;
1464a04a10f8SKris Kennaway }
1465a04a10f8SKris Kennaway 
1466a04a10f8SKris Kennaway int
1467a04a10f8SKris Kennaway session_x11_req(Session *s)
1468a04a10f8SKris Kennaway {
1469a04a10f8SKris Kennaway 	if (!options.x11_forwarding) {
1470a04a10f8SKris Kennaway 		debug("X11 forwarding disabled in server configuration file.");
1471a04a10f8SKris Kennaway 		return 0;
1472a04a10f8SKris Kennaway 	}
1473a04a10f8SKris Kennaway 	if (xauthfile != NULL) {
1474a04a10f8SKris Kennaway 		debug("X11 fwd already started.");
1475a04a10f8SKris Kennaway 		return 0;
1476a04a10f8SKris Kennaway 	}
1477a04a10f8SKris Kennaway 
1478a04a10f8SKris Kennaway 	debug("Received request for X11 forwarding with auth spoofing.");
1479a04a10f8SKris Kennaway 	if (s->display != NULL)
1480a04a10f8SKris Kennaway 		packet_disconnect("Protocol error: X11 display already set.");
1481a04a10f8SKris Kennaway 
1482a04a10f8SKris Kennaway 	s->single_connection = packet_get_char();
1483a04a10f8SKris Kennaway 	s->auth_proto = packet_get_string(NULL);
1484a04a10f8SKris Kennaway 	s->auth_data = packet_get_string(NULL);
1485a04a10f8SKris Kennaway 	s->screen = packet_get_int();
1486a04a10f8SKris Kennaway 	packet_done();
1487a04a10f8SKris Kennaway 
1488a04a10f8SKris Kennaway 	s->display = x11_create_display_inet(s->screen, options.x11_display_offset);
1489a04a10f8SKris Kennaway 	if (s->display == NULL) {
1490a04a10f8SKris Kennaway 		xfree(s->auth_proto);
1491a04a10f8SKris Kennaway 		xfree(s->auth_data);
1492a04a10f8SKris Kennaway 		return 0;
1493a04a10f8SKris Kennaway 	}
1494a04a10f8SKris Kennaway 	xauthfile = xmalloc(MAXPATHLEN);
1495a04a10f8SKris Kennaway 	strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
1496a04a10f8SKris Kennaway 	temporarily_use_uid(s->pw->pw_uid);
1497a04a10f8SKris Kennaway 	if (mkdtemp(xauthfile) == NULL) {
1498a04a10f8SKris Kennaway 		restore_uid();
1499a04a10f8SKris Kennaway 		error("private X11 dir: mkdtemp %s failed: %s",
1500a04a10f8SKris Kennaway 		    xauthfile, strerror(errno));
1501a04a10f8SKris Kennaway 		xfree(xauthfile);
1502a04a10f8SKris Kennaway 		xauthfile = NULL;
1503a04a10f8SKris Kennaway 		xfree(s->auth_proto);
1504a04a10f8SKris Kennaway 		xfree(s->auth_data);
1505a04a10f8SKris Kennaway 		/* XXXX remove listening channels */
1506a04a10f8SKris Kennaway 		return 0;
1507a04a10f8SKris Kennaway 	}
1508a04a10f8SKris Kennaway 	strlcat(xauthfile, "/cookies", MAXPATHLEN);
1509a04a10f8SKris Kennaway 	open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600);
1510a04a10f8SKris Kennaway 	restore_uid();
1511a04a10f8SKris Kennaway 	fatal_add_cleanup(xauthfile_cleanup_proc, s);
1512a04a10f8SKris Kennaway 	return 1;
1513a04a10f8SKris Kennaway }
1514a04a10f8SKris Kennaway 
1515a04a10f8SKris Kennaway void
1516a04a10f8SKris Kennaway session_input_channel_req(int id, void *arg)
1517a04a10f8SKris Kennaway {
1518a04a10f8SKris Kennaway 	unsigned int len;
1519a04a10f8SKris Kennaway 	int reply;
1520a04a10f8SKris Kennaway 	int success = 0;
1521a04a10f8SKris Kennaway 	char *rtype;
1522a04a10f8SKris Kennaway 	Session *s;
1523a04a10f8SKris Kennaway 	Channel *c;
1524a04a10f8SKris Kennaway 
1525a04a10f8SKris Kennaway 	rtype = packet_get_string(&len);
1526a04a10f8SKris Kennaway 	reply = packet_get_char();
1527a04a10f8SKris Kennaway 
1528a04a10f8SKris Kennaway 	s = session_by_channel(id);
1529a04a10f8SKris Kennaway 	if (s == NULL)
1530a04a10f8SKris Kennaway 		fatal("session_input_channel_req: channel %d: no session", id);
1531a04a10f8SKris Kennaway 	c = channel_lookup(id);
1532a04a10f8SKris Kennaway 	if (c == NULL)
1533a04a10f8SKris Kennaway 		fatal("session_input_channel_req: channel %d: bad channel", id);
1534a04a10f8SKris Kennaway 
1535a04a10f8SKris Kennaway 	debug("session_input_channel_req: session %d channel %d request %s reply %d",
1536a04a10f8SKris Kennaway 	    s->self, id, rtype, reply);
1537a04a10f8SKris Kennaway 
1538a04a10f8SKris Kennaway 	/*
1539a04a10f8SKris Kennaway 	 * a session is in LARVAL state until a shell
1540a04a10f8SKris Kennaway 	 * or programm is executed
1541a04a10f8SKris Kennaway 	 */
1542a04a10f8SKris Kennaway 	if (c->type == SSH_CHANNEL_LARVAL) {
1543a04a10f8SKris Kennaway 		if (strcmp(rtype, "shell") == 0) {
1544a04a10f8SKris Kennaway 			packet_done();
1545a04a10f8SKris Kennaway 			s->extended = 1;
1546a04a10f8SKris Kennaway 			if (s->ttyfd == -1)
1547a04a10f8SKris Kennaway 				do_exec_no_pty(s, NULL, s->pw);
1548a04a10f8SKris Kennaway 			else
1549a04a10f8SKris Kennaway 				do_exec_pty(s, NULL, s->pw);
1550a04a10f8SKris Kennaway 			success = 1;
1551a04a10f8SKris Kennaway 		} else if (strcmp(rtype, "exec") == 0) {
1552a04a10f8SKris Kennaway 			char *command = packet_get_string(&len);
1553a04a10f8SKris Kennaway 			packet_done();
1554a04a10f8SKris Kennaway 			s->extended = 1;
1555a04a10f8SKris Kennaway 			if (s->ttyfd == -1)
1556a04a10f8SKris Kennaway 				do_exec_no_pty(s, command, s->pw);
1557a04a10f8SKris Kennaway 			else
1558a04a10f8SKris Kennaway 				do_exec_pty(s, command, s->pw);
1559a04a10f8SKris Kennaway 			xfree(command);
1560a04a10f8SKris Kennaway 			success = 1;
1561a04a10f8SKris Kennaway 		} else if (strcmp(rtype, "pty-req") == 0) {
1562a04a10f8SKris Kennaway 			success =  session_pty_req(s);
1563a04a10f8SKris Kennaway 		} else if (strcmp(rtype, "x11-req") == 0) {
1564a04a10f8SKris Kennaway 			success = session_x11_req(s);
1565a04a10f8SKris Kennaway 		} else if (strcmp(rtype, "subsystem") == 0) {
1566a04a10f8SKris Kennaway 			success = session_subsystem_req(s);
1567a04a10f8SKris Kennaway 		}
1568a04a10f8SKris Kennaway 	}
1569a04a10f8SKris Kennaway 	if (strcmp(rtype, "window-change") == 0) {
1570a04a10f8SKris Kennaway 		success = session_window_change_req(s);
1571a04a10f8SKris Kennaway 	}
1572a04a10f8SKris Kennaway 
1573a04a10f8SKris Kennaway 	if (reply) {
1574a04a10f8SKris Kennaway 		packet_start(success ?
1575a04a10f8SKris Kennaway 		    SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
1576a04a10f8SKris Kennaway 		packet_put_int(c->remote_id);
1577a04a10f8SKris Kennaway 		packet_send();
1578a04a10f8SKris Kennaway 	}
1579a04a10f8SKris Kennaway 	xfree(rtype);
1580a04a10f8SKris Kennaway }
1581a04a10f8SKris Kennaway 
1582a04a10f8SKris Kennaway void
1583a04a10f8SKris Kennaway session_set_fds(Session *s, int fdin, int fdout, int fderr)
1584a04a10f8SKris Kennaway {
1585a04a10f8SKris Kennaway 	if (!compat20)
1586a04a10f8SKris Kennaway 		fatal("session_set_fds: called for proto != 2.0");
1587a04a10f8SKris Kennaway 	/*
1588a04a10f8SKris Kennaway 	 * now that have a child and a pipe to the child,
1589a04a10f8SKris Kennaway 	 * we can activate our channel and register the fd's
1590a04a10f8SKris Kennaway 	 */
1591a04a10f8SKris Kennaway 	if (s->chanid == -1)
1592a04a10f8SKris Kennaway 		fatal("no channel for session %d", s->self);
1593a04a10f8SKris Kennaway 	channel_set_fds(s->chanid,
1594a04a10f8SKris Kennaway 	    fdout, fdin, fderr,
1595a04a10f8SKris Kennaway 	    fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ);
1596a04a10f8SKris Kennaway }
1597a04a10f8SKris Kennaway 
1598a04a10f8SKris Kennaway void
1599a04a10f8SKris Kennaway session_pty_cleanup(Session *s)
1600a04a10f8SKris Kennaway {
1601a04a10f8SKris Kennaway 	if (s == NULL || s->ttyfd == -1)
1602a04a10f8SKris Kennaway 		return;
1603a04a10f8SKris Kennaway 
1604a04a10f8SKris Kennaway 	debug("session_pty_cleanup: session %i release %s", s->self, s->tty);
1605a04a10f8SKris Kennaway 
1606a04a10f8SKris Kennaway 	/* Cancel the cleanup function. */
1607a04a10f8SKris Kennaway 	fatal_remove_cleanup(pty_cleanup_proc, (void *)s);
1608a04a10f8SKris Kennaway 
1609a04a10f8SKris Kennaway 	/* Record that the user has logged out. */
1610a04a10f8SKris Kennaway 	record_logout(s->pid, s->tty);
1611a04a10f8SKris Kennaway 
1612a04a10f8SKris Kennaway 	/* Release the pseudo-tty. */
1613a04a10f8SKris Kennaway 	pty_release(s->tty);
1614a04a10f8SKris Kennaway 
1615a04a10f8SKris Kennaway 	/*
1616a04a10f8SKris Kennaway 	 * Close the server side of the socket pairs.  We must do this after
1617a04a10f8SKris Kennaway 	 * the pty cleanup, so that another process doesn't get this pty
1618a04a10f8SKris Kennaway 	 * while we're still cleaning up.
1619a04a10f8SKris Kennaway 	 */
1620a04a10f8SKris Kennaway 	if (close(s->ptymaster) < 0)
1621a04a10f8SKris Kennaway 		error("close(s->ptymaster): %s", strerror(errno));
1622a04a10f8SKris Kennaway }
1623a04a10f8SKris Kennaway 
1624a04a10f8SKris Kennaway void
1625a04a10f8SKris Kennaway session_exit_message(Session *s, int status)
1626a04a10f8SKris Kennaway {
1627a04a10f8SKris Kennaway 	Channel *c;
1628a04a10f8SKris Kennaway 	if (s == NULL)
1629a04a10f8SKris Kennaway 		fatal("session_close: no session");
1630a04a10f8SKris Kennaway 	c = channel_lookup(s->chanid);
1631a04a10f8SKris Kennaway 	if (c == NULL)
1632a04a10f8SKris Kennaway 		fatal("session_close: session %d: no channel %d",
1633a04a10f8SKris Kennaway 		    s->self, s->chanid);
1634a04a10f8SKris Kennaway 	debug("session_exit_message: session %d channel %d pid %d",
1635a04a10f8SKris Kennaway 	    s->self, s->chanid, s->pid);
1636a04a10f8SKris Kennaway 
1637a04a10f8SKris Kennaway 	if (WIFEXITED(status)) {
1638a04a10f8SKris Kennaway 		channel_request_start(s->chanid,
1639a04a10f8SKris Kennaway 		    "exit-status", 0);
1640a04a10f8SKris Kennaway 		packet_put_int(WEXITSTATUS(status));
1641a04a10f8SKris Kennaway 		packet_send();
1642a04a10f8SKris Kennaway 	} else if (WIFSIGNALED(status)) {
1643a04a10f8SKris Kennaway 		channel_request_start(s->chanid,
1644a04a10f8SKris Kennaway 		    "exit-signal", 0);
1645a04a10f8SKris Kennaway 		packet_put_int(WTERMSIG(status));
1646a04a10f8SKris Kennaway 		packet_put_char(WCOREDUMP(status));
1647a04a10f8SKris Kennaway 		packet_put_cstring("");
1648a04a10f8SKris Kennaway 		packet_put_cstring("");
1649a04a10f8SKris Kennaway 		packet_send();
1650a04a10f8SKris Kennaway 	} else {
1651a04a10f8SKris Kennaway 		/* Some weird exit cause.  Just exit. */
1652a04a10f8SKris Kennaway 		packet_disconnect("wait returned status %04x.", status);
1653a04a10f8SKris Kennaway 	}
1654a04a10f8SKris Kennaway 
1655a04a10f8SKris Kennaway 	/* disconnect channel */
1656a04a10f8SKris Kennaway 	debug("session_exit_message: release channel %d", s->chanid);
1657a04a10f8SKris Kennaway 	channel_cancel_cleanup(s->chanid);
1658a04a10f8SKris Kennaway 	/*
1659a04a10f8SKris Kennaway 	 * emulate a write failure with 'chan_write_failed', nobody will be
1660a04a10f8SKris Kennaway 	 * interested in data we write.
1661a04a10f8SKris Kennaway 	 * Note that we must not call 'chan_read_failed', since there could
1662a04a10f8SKris Kennaway 	 * be some more data waiting in the pipe.
1663a04a10f8SKris Kennaway 	 */
1664a04a10f8SKris Kennaway 	if (c->ostate != CHAN_OUTPUT_CLOSED)
1665a04a10f8SKris Kennaway 		chan_write_failed(c);
1666a04a10f8SKris Kennaway 	s->chanid = -1;
1667a04a10f8SKris Kennaway }
1668a04a10f8SKris Kennaway 
1669a04a10f8SKris Kennaway void
1670a04a10f8SKris Kennaway session_free(Session *s)
1671a04a10f8SKris Kennaway {
1672a04a10f8SKris Kennaway 	debug("session_free: session %d pid %d", s->self, s->pid);
1673a04a10f8SKris Kennaway 	if (s->term)
1674a04a10f8SKris Kennaway 		xfree(s->term);
1675a04a10f8SKris Kennaway 	if (s->display)
1676a04a10f8SKris Kennaway 		xfree(s->display);
1677a04a10f8SKris Kennaway 	if (s->auth_data)
1678a04a10f8SKris Kennaway 		xfree(s->auth_data);
1679a04a10f8SKris Kennaway 	if (s->auth_proto)
1680a04a10f8SKris Kennaway 		xfree(s->auth_proto);
1681a04a10f8SKris Kennaway 	s->used = 0;
1682a04a10f8SKris Kennaway }
1683a04a10f8SKris Kennaway 
1684a04a10f8SKris Kennaway void
1685a04a10f8SKris Kennaway session_close(Session *s)
1686a04a10f8SKris Kennaway {
1687a04a10f8SKris Kennaway 	session_pty_cleanup(s);
1688a04a10f8SKris Kennaway 	session_free(s);
1689a04a10f8SKris Kennaway 	session_proctitle(s);
1690a04a10f8SKris Kennaway }
1691a04a10f8SKris Kennaway 
1692a04a10f8SKris Kennaway void
1693a04a10f8SKris Kennaway session_close_by_pid(pid_t pid, int status)
1694a04a10f8SKris Kennaway {
1695a04a10f8SKris Kennaway 	Session *s = session_by_pid(pid);
1696a04a10f8SKris Kennaway 	if (s == NULL) {
1697a04a10f8SKris Kennaway 		debug("session_close_by_pid: no session for pid %d", s->pid);
1698a04a10f8SKris Kennaway 		return;
1699a04a10f8SKris Kennaway 	}
1700a04a10f8SKris Kennaway 	if (s->chanid != -1)
1701a04a10f8SKris Kennaway 		session_exit_message(s, status);
1702a04a10f8SKris Kennaway 	session_close(s);
1703a04a10f8SKris Kennaway }
1704a04a10f8SKris Kennaway 
1705a04a10f8SKris Kennaway /*
1706a04a10f8SKris Kennaway  * this is called when a channel dies before
1707a04a10f8SKris Kennaway  * the session 'child' itself dies
1708a04a10f8SKris Kennaway  */
1709a04a10f8SKris Kennaway void
1710a04a10f8SKris Kennaway session_close_by_channel(int id, void *arg)
1711a04a10f8SKris Kennaway {
1712a04a10f8SKris Kennaway 	Session *s = session_by_channel(id);
1713a04a10f8SKris Kennaway 	if (s == NULL) {
1714a04a10f8SKris Kennaway 		debug("session_close_by_channel: no session for channel %d", id);
1715a04a10f8SKris Kennaway 		return;
1716a04a10f8SKris Kennaway 	}
1717a04a10f8SKris Kennaway 	/* disconnect channel */
1718a04a10f8SKris Kennaway 	channel_cancel_cleanup(s->chanid);
1719a04a10f8SKris Kennaway 	s->chanid = -1;
1720a04a10f8SKris Kennaway 
1721a04a10f8SKris Kennaway 	debug("session_close_by_channel: channel %d kill %d", id, s->pid);
1722a04a10f8SKris Kennaway 	if (s->pid == 0) {
1723a04a10f8SKris Kennaway 		/* close session immediately */
1724a04a10f8SKris Kennaway 		session_close(s);
1725a04a10f8SKris Kennaway 	} else {
1726a04a10f8SKris Kennaway 		/* notify child, delay session cleanup */
1727a04a10f8SKris Kennaway 		if (kill(s->pid, (s->ttyfd == -1) ? SIGTERM : SIGHUP) < 0)
1728a04a10f8SKris Kennaway 			error("session_close_by_channel: kill %d: %s",
1729a04a10f8SKris Kennaway 			    s->pid, strerror(errno));
1730a04a10f8SKris Kennaway 	}
1731a04a10f8SKris Kennaway }
1732a04a10f8SKris Kennaway 
1733a04a10f8SKris Kennaway char *
1734a04a10f8SKris Kennaway session_tty_list(void)
1735a04a10f8SKris Kennaway {
1736a04a10f8SKris Kennaway 	static char buf[1024];
1737a04a10f8SKris Kennaway 	int i;
1738a04a10f8SKris Kennaway 	buf[0] = '\0';
1739a04a10f8SKris Kennaway 	for(i = 0; i < MAX_SESSIONS; i++) {
1740a04a10f8SKris Kennaway 		Session *s = &sessions[i];
1741a04a10f8SKris Kennaway 		if (s->used && s->ttyfd != -1) {
1742a04a10f8SKris Kennaway 			if (buf[0] != '\0')
1743a04a10f8SKris Kennaway 				strlcat(buf, ",", sizeof buf);
1744a04a10f8SKris Kennaway 			strlcat(buf, strrchr(s->tty, '/') + 1, sizeof buf);
1745a04a10f8SKris Kennaway 		}
1746a04a10f8SKris Kennaway 	}
1747a04a10f8SKris Kennaway 	if (buf[0] == '\0')
1748a04a10f8SKris Kennaway 		strlcpy(buf, "notty", sizeof buf);
1749a04a10f8SKris Kennaway 	return buf;
1750a04a10f8SKris Kennaway }
1751a04a10f8SKris Kennaway 
1752a04a10f8SKris Kennaway void
1753a04a10f8SKris Kennaway session_proctitle(Session *s)
1754a04a10f8SKris Kennaway {
1755a04a10f8SKris Kennaway 	if (s->pw == NULL)
1756a04a10f8SKris Kennaway 		error("no user for session %d", s->self);
1757a04a10f8SKris Kennaway 	else
1758a04a10f8SKris Kennaway 		setproctitle("%s@%s", s->pw->pw_name, session_tty_list());
1759a04a10f8SKris Kennaway }
1760a04a10f8SKris Kennaway 
1761a04a10f8SKris Kennaway void
1762a04a10f8SKris Kennaway do_authenticated2(void)
1763a04a10f8SKris Kennaway {
1764a04a10f8SKris Kennaway 	/*
1765a04a10f8SKris Kennaway 	 * Cancel the alarm we set to limit the time taken for
1766a04a10f8SKris Kennaway 	 * authentication.
1767a04a10f8SKris Kennaway 	 */
1768a04a10f8SKris Kennaway 	alarm(0);
1769a04a10f8SKris Kennaway 	server_loop2();
1770a04a10f8SKris Kennaway 	if (xauthfile)
1771a04a10f8SKris Kennaway 		xauthfile_cleanup_proc(NULL);
1772a04a10f8SKris Kennaway }
1773