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