blob: 3c4e9c4409fb837febeddc848146d11ddb0cdf65 [file] [log] [blame]
djm@openbsd.org95344c22018-07-03 10:59:35 +00001/* $OpenBSD: session.c,v 1.301 2018/07/03 10:59:35 djm Exp $ */
Damien Millerb38eff82000-04-01 11:09:21 +10002/*
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 * All rights reserved
Damien Millere4340be2000-09-16 13:29:08 +11005 *
6 * As far as I am concerned, the code I have written for this software
7 * can be used freely for any purpose. Any derived versions of this
8 * software must be clearly marked as such, and if the derived work is
9 * incompatible with the protocol description in the RFC file, it must be
10 * called by a name other than "ssh" or "Secure Shell".
11 *
Damien Millerefb4afe2000-04-12 18:45:05 +100012 * SSH2 support by Markus Friedl.
Ben Lindstrom44697232001-07-04 03:32:30 +000013 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
Damien Millere4340be2000-09-16 13:29:08 +110014 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Damien Millerefb4afe2000-04-12 18:45:05 +100034 */
Damien Millerb38eff82000-04-01 11:09:21 +100035
36#include "includes.h"
Damien Miller9cf6d072006-03-15 11:29:24 +110037
38#include <sys/types.h>
Damien Miller8dbffe72006-08-05 11:02:17 +100039#include <sys/param.h>
Damien Millerf17883e2006-03-15 11:45:54 +110040#ifdef HAVE_SYS_STAT_H
41# include <sys/stat.h>
42#endif
Damien Millere3b60b52006-07-10 21:08:03 +100043#include <sys/socket.h>
Damien Miller574c41f2006-03-15 11:40:10 +110044#include <sys/un.h>
Damien Miller8dbffe72006-08-05 11:02:17 +100045#include <sys/wait.h>
Damien Miller03e20032006-03-15 11:16:59 +110046
Damien Miller1cdde6f2006-07-24 14:07:35 +100047#include <arpa/inet.h>
48
djm@openbsd.org4b4bfb02016-03-10 11:47:57 +000049#include <ctype.h>
Darren Tucker39972492006-07-12 22:22:46 +100050#include <errno.h>
Damien Miller22a29882010-05-10 11:53:54 +100051#include <fcntl.h>
Damien Miller427a1d52006-07-10 20:20:33 +100052#include <grp.h>
Damien Millere5c0d522014-07-03 21:24:19 +100053#include <netdb.h>
Damien Miller6645e7a2006-03-15 14:42:54 +110054#ifdef HAVE_PATHS_H
Damien Miller03e20032006-03-15 11:16:59 +110055#include <paths.h>
Damien Miller6645e7a2006-03-15 14:42:54 +110056#endif
Damien Miller9f2abc42006-07-10 20:53:08 +100057#include <pwd.h>
Damien Miller6ff3cad2006-03-15 11:52:09 +110058#include <signal.h>
Damien Millerded319c2006-09-01 15:38:36 +100059#include <stdarg.h>
Damien Millera7a73ee2006-08-05 11:37:59 +100060#include <stdio.h>
Damien Millere7a1e5c2006-08-05 11:34:19 +100061#include <stdlib.h>
Damien Millere3476ed2006-07-24 14:13:33 +100062#include <string.h>
Damien Miller1cdde6f2006-07-24 14:07:35 +100063#include <unistd.h>
deraadt@openbsd.org2ae4f332015-01-16 06:40:12 +000064#include <limits.h>
Damien Millerb38eff82000-04-01 11:09:21 +100065
Damien Millerb84886b2008-05-19 15:05:07 +100066#include "openbsd-compat/sys-queue.h"
Damien Millerd7834352006-08-05 12:39:39 +100067#include "xmalloc.h"
Damien Millerb38eff82000-04-01 11:09:21 +100068#include "ssh.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000069#include "ssh2.h"
Ben Lindstromd95c09c2001-02-18 19:13:33 +000070#include "sshpty.h"
Damien Millerb38eff82000-04-01 11:09:21 +100071#include "packet.h"
72#include "buffer.h"
Darren Tucker46bc0752004-05-02 22:11:30 +100073#include "match.h"
Damien Millerb38eff82000-04-01 11:09:21 +100074#include "uidswap.h"
75#include "compat.h"
Ben Lindstromc7637672001-06-09 00:36:26 +000076#include "channels.h"
Damien Millerd7834352006-08-05 12:39:39 +100077#include "key.h"
78#include "cipher.h"
79#ifdef GSSAPI
80#include "ssh-gss.h"
81#endif
82#include "hostfile.h"
Damien Millerefb4afe2000-04-12 18:45:05 +100083#include "auth.h"
Damien Millerf6d9e222000-06-18 14:50:44 +100084#include "auth-options.h"
Damien Miller85b45e02013-07-20 13:21:52 +100085#include "authfd.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000086#include "pathnames.h"
87#include "log.h"
Damien Miller7acefbb2014-07-18 14:11:24 +100088#include "misc.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000089#include "servconf.h"
Ben Lindstromd95c09c2001-02-18 19:13:33 +000090#include "sshlogin.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000091#include "serverloop.h"
92#include "canohost.h"
Ben Lindstrom31ca54a2001-02-09 02:11:24 +000093#include "session.h"
Damien Miller9786e6e2005-07-26 21:54:56 +100094#include "kex.h"
Ben Lindstrom7a2073c2002-03-22 02:30:41 +000095#include "monitor_wrap.h"
Damien Millerdfc24252008-02-10 22:29:40 +110096#include "sftp.h"
djm@openbsd.org8f574952017-06-24 06:34:38 +000097#include "atomicio.h"
Damien Millerefb4afe2000-04-12 18:45:05 +100098
Darren Tucker3c78c5e2004-01-23 22:03:10 +110099#if defined(KRB5) && defined(USE_AFS)
Damien Miller8f341f82004-01-21 11:00:46 +1100100#include <kafs.h>
101#endif
102
Damien Miller14684a12011-05-20 11:23:07 +1000103#ifdef WITH_SELINUX
104#include <selinux/selinux.h>
105#endif
106
Damien Millerad793d52008-11-03 19:17:57 +1100107#define IS_INTERNAL_SFTP(c) \
108 (!strncmp(c, INTERNAL_SFTP_NAME, sizeof(INTERNAL_SFTP_NAME) - 1) && \
109 (c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\0' || \
110 c[sizeof(INTERNAL_SFTP_NAME) - 1] == ' ' || \
111 c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\t'))
112
Damien Millerb38eff82000-04-01 11:09:21 +1000113/* func */
114
115Session *session_new(void);
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000116void session_set_fds(struct ssh *, Session *, int, int, int, int, int);
Darren Tucker3e33cec2003-10-02 16:12:36 +1000117void session_pty_cleanup(Session *);
Kevin Steves8f63caa2001-07-04 18:23:02 +0000118void session_proctitle(Session *);
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000119int session_setup_x11fwd(struct ssh *, Session *);
120int do_exec_pty(struct ssh *, Session *, const char *);
121int do_exec_no_pty(struct ssh *, Session *, const char *);
122int do_exec(struct ssh *, Session *, const char *);
123void do_login(struct ssh *, Session *, const char *);
124void do_child(struct ssh *, Session *, const char *);
Kevin Stevesa0957d62001-09-27 19:50:26 +0000125#ifdef LOGIN_NEEDS_UTMPX
126static void do_pre_login(Session *s);
127#endif
Damien Millercf205e82001-04-16 18:29:15 +1000128void do_motd(void);
Kevin Steves8f63caa2001-07-04 18:23:02 +0000129int check_quietlogin(Session *, const char *);
Damien Millerb38eff82000-04-01 11:09:21 +1000130
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000131static void do_authenticated2(struct ssh *, Authctxt *);
Kevin Steves8f63caa2001-07-04 18:23:02 +0000132
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000133static int session_pty_req(struct ssh *, Session *);
Ben Lindstromb31783d2001-03-22 02:02:12 +0000134
Damien Millerb38eff82000-04-01 11:09:21 +1000135/* import */
136extern ServerOptions options;
137extern char *__progname;
Damien Millerb38eff82000-04-01 11:09:21 +1000138extern int debug_flag;
Ben Lindstrom46c16222000-12-22 01:43:59 +0000139extern u_int utmp_len;
Damien Miller37023962000-07-11 17:31:38 +1000140extern int startup_pipe;
Ben Lindstrom005dd222001-04-18 15:29:33 +0000141extern void destroy_sensitive_data(void);
Darren Tuckerb9aa0a02003-07-08 22:59:59 +1000142extern Buffer loginmsg;
djm@openbsd.org7c856852018-03-03 03:15:51 +0000143extern struct sshauthopt *auth_opts;
djm@openbsd.orgb7548b12017-10-23 05:08:00 +0000144char *tun_fwd_ifnames; /* serverloop.c */
Damien Miller37023962000-07-11 17:31:38 +1000145
Damien Miller7b28dc52000-09-05 13:34:53 +1100146/* original command from peer. */
Ben Lindstrom0a7ca6c2001-06-21 03:17:42 +0000147const char *original_command = NULL;
Damien Miller7b28dc52000-09-05 13:34:53 +1100148
Damien Millerb38eff82000-04-01 11:09:21 +1000149/* data */
Damien Miller7207f642008-05-19 15:34:50 +1000150static int sessions_first_unused = -1;
151static int sessions_nalloc = 0;
152static Session *sessions = NULL;
Damien Miller15e7d4b2000-09-29 10:57:35 +1100153
Darren Tuckerd6b06a92010-01-08 17:09:11 +1100154#define SUBSYSTEM_NONE 0
155#define SUBSYSTEM_EXT 1
156#define SUBSYSTEM_INT_SFTP 2
157#define SUBSYSTEM_INT_SFTP_ERROR 3
Damien Millerdfc24252008-02-10 22:29:40 +1100158
Damien Millerad833b32000-08-23 10:46:23 +1000159#ifdef HAVE_LOGIN_CAP
Ben Lindstromb481e132002-03-22 01:35:47 +0000160login_cap_t *lc;
Damien Millerad833b32000-08-23 10:46:23 +1000161#endif
162
Darren Tucker3e33cec2003-10-02 16:12:36 +1000163static int is_child = 0;
djm@openbsd.org44fc7cd2015-10-24 22:52:22 +0000164static int in_chroot = 0;
Darren Tucker3e33cec2003-10-02 16:12:36 +1000165
djm@openbsd.org8f574952017-06-24 06:34:38 +0000166/* File containing userauth info, if ExposeAuthInfo set */
167static char *auth_info_file = NULL;
168
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000169/* Name and directory of socket for authentication agent forwarding. */
170static char *auth_sock_name = NULL;
171static char *auth_sock_dir = NULL;
172
173/* removes the agent forwarding socket */
174
175static void
Darren Tucker3e33cec2003-10-02 16:12:36 +1000176auth_sock_cleanup_proc(struct passwd *pw)
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000177{
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000178 if (auth_sock_name != NULL) {
179 temporarily_use_uid(pw);
180 unlink(auth_sock_name);
181 rmdir(auth_sock_dir);
182 auth_sock_name = NULL;
183 restore_uid();
184 }
185}
186
187static int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000188auth_input_request_forwarding(struct ssh *ssh, struct passwd * pw)
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000189{
190 Channel *nc;
Damien Miller7207f642008-05-19 15:34:50 +1000191 int sock = -1;
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000192
193 if (auth_sock_name != NULL) {
194 error("authentication forwarding requested twice.");
195 return 0;
196 }
197
198 /* Temporarily drop privileged uid for mkdir/bind. */
199 temporarily_use_uid(pw);
200
201 /* Allocate a buffer for the socket name, and format the name. */
Damien Miller7207f642008-05-19 15:34:50 +1000202 auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX");
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000203
204 /* Create private directory for socket */
205 if (mkdtemp(auth_sock_dir) == NULL) {
206 packet_send_debug("Agent forwarding disabled: "
207 "mkdtemp() failed: %.100s", strerror(errno));
208 restore_uid();
Darren Tuckera627d422013-06-02 07:31:17 +1000209 free(auth_sock_dir);
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000210 auth_sock_dir = NULL;
Damien Miller7207f642008-05-19 15:34:50 +1000211 goto authsock_err;
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000212 }
Damien Miller7207f642008-05-19 15:34:50 +1000213
214 xasprintf(&auth_sock_name, "%s/agent.%ld",
215 auth_sock_dir, (long) getpid());
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000216
Damien Miller7acefbb2014-07-18 14:11:24 +1000217 /* Start a Unix listener on auth_sock_name. */
218 sock = unix_listener(auth_sock_name, SSH_LISTEN_BACKLOG, 0);
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000219
220 /* Restore the privileged uid. */
221 restore_uid();
222
Damien Miller7acefbb2014-07-18 14:11:24 +1000223 /* Check for socket/bind/listen failure. */
224 if (sock < 0)
Damien Miller7207f642008-05-19 15:34:50 +1000225 goto authsock_err;
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000226
227 /* Allocate a channel for the authentication agent socket. */
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000228 nc = channel_new(ssh, "auth socket",
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000229 SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,
230 CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
Damien Millerb1ca8bb2003-05-14 13:45:42 +1000231 0, "auth socket", 1);
Damien Millera1c1b6c2009-01-28 16:29:49 +1100232 nc->path = xstrdup(auth_sock_name);
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000233 return 1;
Damien Miller7207f642008-05-19 15:34:50 +1000234
235 authsock_err:
Darren Tuckera627d422013-06-02 07:31:17 +1000236 free(auth_sock_name);
Damien Miller7207f642008-05-19 15:34:50 +1000237 if (auth_sock_dir != NULL) {
238 rmdir(auth_sock_dir);
Darren Tuckera627d422013-06-02 07:31:17 +1000239 free(auth_sock_dir);
Damien Miller7207f642008-05-19 15:34:50 +1000240 }
241 if (sock != -1)
242 close(sock);
243 auth_sock_name = NULL;
244 auth_sock_dir = NULL;
245 return 0;
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000246}
247
Darren Tucker1921ed92004-02-10 13:23:28 +1100248static void
249display_loginmsg(void)
250{
Damien Miller46d38de2005-07-17 17:02:09 +1000251 if (buffer_len(&loginmsg) > 0) {
252 buffer_append(&loginmsg, "\0", 1);
253 printf("%s", (char *)buffer_ptr(&loginmsg));
254 buffer_clear(&loginmsg);
255 }
Darren Tucker1921ed92004-02-10 13:23:28 +1100256}
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000257
djm@openbsd.org8f574952017-06-24 06:34:38 +0000258static void
259prepare_auth_info_file(struct passwd *pw, struct sshbuf *info)
260{
261 int fd = -1, success = 0;
262
263 if (!options.expose_userauth_info || info == NULL)
264 return;
265
266 temporarily_use_uid(pw);
267 auth_info_file = xstrdup("/tmp/sshauth.XXXXXXXXXXXXXXX");
268 if ((fd = mkstemp(auth_info_file)) == -1) {
269 error("%s: mkstemp: %s", __func__, strerror(errno));
270 goto out;
271 }
272 if (atomicio(vwrite, fd, sshbuf_mutable_ptr(info),
273 sshbuf_len(info)) != sshbuf_len(info)) {
274 error("%s: write: %s", __func__, strerror(errno));
275 goto out;
276 }
277 if (close(fd) != 0) {
278 error("%s: close: %s", __func__, strerror(errno));
279 goto out;
280 }
281 success = 1;
282 out:
283 if (!success) {
284 if (fd != -1)
285 close(fd);
286 free(auth_info_file);
287 auth_info_file = NULL;
288 }
289 restore_uid();
290}
291
djm@openbsd.org7c856852018-03-03 03:15:51 +0000292static void
djm@openbsd.org93c06ab2018-06-06 18:23:32 +0000293set_fwdpermit_from_authopts(struct ssh *ssh, const struct sshauthopt *opts)
djm@openbsd.org7c856852018-03-03 03:15:51 +0000294{
295 char *tmp, *cp, *host;
296 int port;
297 size_t i;
298
djm@openbsd.org93c06ab2018-06-06 18:23:32 +0000299 if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0) {
300 channel_clear_permission(ssh, FORWARD_USER, FORWARD_LOCAL);
301 for (i = 0; i < auth_opts->npermitopen; i++) {
302 tmp = cp = xstrdup(auth_opts->permitopen[i]);
303 /* This shouldn't fail as it has already been checked */
304 if ((host = hpdelim(&cp)) == NULL)
305 fatal("%s: internal error: hpdelim", __func__);
306 host = cleanhostname(host);
307 if (cp == NULL || (port = permitopen_port(cp)) < 0)
308 fatal("%s: internal error: permitopen port",
309 __func__);
310 channel_add_permission(ssh,
311 FORWARD_USER, FORWARD_LOCAL, host, port);
312 free(tmp);
313 }
314 }
315 if ((options.allow_tcp_forwarding & FORWARD_REMOTE) != 0) {
316 channel_clear_permission(ssh, FORWARD_USER, FORWARD_REMOTE);
317 for (i = 0; i < auth_opts->npermitlisten; i++) {
318 tmp = cp = xstrdup(auth_opts->permitlisten[i]);
319 /* This shouldn't fail as it has already been checked */
320 if ((host = hpdelim(&cp)) == NULL)
321 fatal("%s: internal error: hpdelim", __func__);
322 host = cleanhostname(host);
323 if (cp == NULL || (port = permitopen_port(cp)) < 0)
324 fatal("%s: internal error: permitlisten port",
325 __func__);
326 channel_add_permission(ssh,
327 FORWARD_USER, FORWARD_REMOTE, host, port);
328 free(tmp);
329 }
djm@openbsd.org7c856852018-03-03 03:15:51 +0000330 }
331}
332
Ben Lindstromb31783d2001-03-22 02:02:12 +0000333void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000334do_authenticated(struct ssh *ssh, Authctxt *authctxt)
Ben Lindstromb31783d2001-03-22 02:02:12 +0000335{
Damien Miller97f39ae2003-02-24 11:57:01 +1100336 setproctitle("%s", authctxt->pw->pw_name);
337
djm@openbsd.org7c856852018-03-03 03:15:51 +0000338 auth_log_authopts("active", auth_opts, 0);
339
Ben Lindstromb31783d2001-03-22 02:02:12 +0000340 /* setup the channel layer */
Damien Miller7acefbb2014-07-18 14:11:24 +1000341 /* XXX - streamlocal? */
djm@openbsd.org93c06ab2018-06-06 18:23:32 +0000342 set_fwdpermit_from_authopts(ssh, auth_opts);
Ben Lindstromb31783d2001-03-22 02:02:12 +0000343
djm@openbsd.org115063a2018-06-06 18:22:41 +0000344 if (!auth_opts->permit_port_forwarding_flag ||
345 options.disable_forwarding) {
346 channel_disable_admin(ssh, FORWARD_LOCAL);
347 channel_disable_admin(ssh, FORWARD_REMOTE);
348 } else {
349 if ((options.allow_tcp_forwarding & FORWARD_LOCAL) == 0)
350 channel_disable_admin(ssh, FORWARD_LOCAL);
351 else
352 channel_permit_all(ssh, FORWARD_LOCAL);
353 if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0)
354 channel_disable_admin(ssh, FORWARD_REMOTE);
355 else
356 channel_permit_all(ssh, FORWARD_REMOTE);
357 }
Darren Tuckercd70e1b2010-03-07 23:05:17 +1100358 auth_debug_send();
359
djm@openbsd.org8f574952017-06-24 06:34:38 +0000360 prepare_auth_info_file(authctxt->pw, authctxt->session_info);
361
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000362 do_authenticated2(ssh, authctxt);
djm@openbsd.org8f574952017-06-24 06:34:38 +0000363
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000364 do_cleanup(ssh, authctxt);
Ben Lindstromb31783d2001-03-22 02:02:12 +0000365}
366
djm@openbsd.org4b4bfb02016-03-10 11:47:57 +0000367/* Check untrusted xauth strings for metacharacters */
368static int
369xauth_valid_string(const char *s)
370{
371 size_t i;
372
373 for (i = 0; s[i] != '\0'; i++) {
374 if (!isalnum((u_char)s[i]) &&
375 s[i] != '.' && s[i] != ':' && s[i] != '/' &&
376 s[i] != '-' && s[i] != '_')
377 return 0;
378 }
379 return 1;
380}
381
Darren Tucker293ee3c2014-01-19 15:28:01 +1100382#define USE_PIPES 1
Damien Millerb38eff82000-04-01 11:09:21 +1000383/*
384 * This is called to fork and execute a command when we have no tty. This
385 * will call do_child from the child, and server_loop from the parent after
386 * setting up file descriptors and such.
387 */
Damien Miller7207f642008-05-19 15:34:50 +1000388int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000389do_exec_no_pty(struct ssh *ssh, Session *s, const char *command)
Damien Millerb38eff82000-04-01 11:09:21 +1000390{
Ben Lindstromce0f6342002-06-11 16:42:49 +0000391 pid_t pid;
Damien Millerb38eff82000-04-01 11:09:21 +1000392#ifdef USE_PIPES
393 int pin[2], pout[2], perr[2];
Damien Miller7207f642008-05-19 15:34:50 +1000394
Damien Miller22a29882010-05-10 11:53:54 +1000395 if (s == NULL)
396 fatal("do_exec_no_pty: no session");
397
Damien Millerb38eff82000-04-01 11:09:21 +1000398 /* Allocate pipes for communicating with the program. */
Damien Miller7207f642008-05-19 15:34:50 +1000399 if (pipe(pin) < 0) {
400 error("%s: pipe in: %.100s", __func__, strerror(errno));
401 return -1;
402 }
403 if (pipe(pout) < 0) {
404 error("%s: pipe out: %.100s", __func__, strerror(errno));
405 close(pin[0]);
406 close(pin[1]);
407 return -1;
408 }
Damien Miller8853ca52010-06-26 10:00:14 +1000409 if (pipe(perr) < 0) {
410 error("%s: pipe err: %.100s", __func__,
411 strerror(errno));
412 close(pin[0]);
413 close(pin[1]);
414 close(pout[0]);
415 close(pout[1]);
416 return -1;
Damien Miller7207f642008-05-19 15:34:50 +1000417 }
418#else
Damien Millerb38eff82000-04-01 11:09:21 +1000419 int inout[2], err[2];
Damien Miller7207f642008-05-19 15:34:50 +1000420
Damien Miller22a29882010-05-10 11:53:54 +1000421 if (s == NULL)
422 fatal("do_exec_no_pty: no session");
423
Damien Millerb38eff82000-04-01 11:09:21 +1000424 /* Uses socket pairs to communicate with the program. */
Damien Miller7207f642008-05-19 15:34:50 +1000425 if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0) {
426 error("%s: socketpair #1: %.100s", __func__, strerror(errno));
427 return -1;
428 }
Damien Miller8853ca52010-06-26 10:00:14 +1000429 if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) {
430 error("%s: socketpair #2: %.100s", __func__,
431 strerror(errno));
432 close(inout[0]);
433 close(inout[1]);
434 return -1;
Damien Miller7207f642008-05-19 15:34:50 +1000435 }
436#endif
437
Damien Millere247cc42000-05-07 12:03:14 +1000438 session_proctitle(s);
Damien Millerb38eff82000-04-01 11:09:21 +1000439
Damien Millerb38eff82000-04-01 11:09:21 +1000440 /* Fork the child. */
Damien Miller7207f642008-05-19 15:34:50 +1000441 switch ((pid = fork())) {
442 case -1:
443 error("%s: fork: %.100s", __func__, strerror(errno));
444#ifdef USE_PIPES
445 close(pin[0]);
446 close(pin[1]);
447 close(pout[0]);
448 close(pout[1]);
Damien Miller8853ca52010-06-26 10:00:14 +1000449 close(perr[0]);
Damien Miller7207f642008-05-19 15:34:50 +1000450 close(perr[1]);
451#else
452 close(inout[0]);
453 close(inout[1]);
454 close(err[0]);
Damien Miller8853ca52010-06-26 10:00:14 +1000455 close(err[1]);
Damien Miller7207f642008-05-19 15:34:50 +1000456#endif
457 return -1;
458 case 0:
Darren Tucker3e33cec2003-10-02 16:12:36 +1000459 is_child = 1;
Ben Lindstrom264ee302002-07-23 21:01:56 +0000460
Damien Millerb38eff82000-04-01 11:09:21 +1000461 /*
462 * Create a new session and process group since the 4.4BSD
463 * setlogin() affects the entire process group.
464 */
465 if (setsid() < 0)
466 error("setsid failed: %.100s", strerror(errno));
467
468#ifdef USE_PIPES
469 /*
470 * Redirect stdin. We close the parent side of the socket
471 * pair, and make the child side the standard input.
472 */
473 close(pin[1]);
474 if (dup2(pin[0], 0) < 0)
475 perror("dup2 stdin");
476 close(pin[0]);
477
478 /* Redirect stdout. */
479 close(pout[0]);
480 if (dup2(pout[1], 1) < 0)
481 perror("dup2 stdout");
482 close(pout[1]);
483
484 /* Redirect stderr. */
Damien Miller8853ca52010-06-26 10:00:14 +1000485 close(perr[0]);
Damien Millerb38eff82000-04-01 11:09:21 +1000486 if (dup2(perr[1], 2) < 0)
487 perror("dup2 stderr");
488 close(perr[1]);
Damien Miller7207f642008-05-19 15:34:50 +1000489#else
Damien Millerb38eff82000-04-01 11:09:21 +1000490 /*
491 * Redirect stdin, stdout, and stderr. Stdin and stdout will
492 * use the same socket, as some programs (particularly rdist)
493 * seem to depend on it.
494 */
495 close(inout[1]);
Damien Miller8853ca52010-06-26 10:00:14 +1000496 close(err[1]);
Damien Millerb38eff82000-04-01 11:09:21 +1000497 if (dup2(inout[0], 0) < 0) /* stdin */
498 perror("dup2 stdin");
Damien Miller7207f642008-05-19 15:34:50 +1000499 if (dup2(inout[0], 1) < 0) /* stdout (same as stdin) */
Damien Millerb38eff82000-04-01 11:09:21 +1000500 perror("dup2 stdout");
Damien Miller7207f642008-05-19 15:34:50 +1000501 close(inout[0]);
Damien Millerb38eff82000-04-01 11:09:21 +1000502 if (dup2(err[0], 2) < 0) /* stderr */
503 perror("dup2 stderr");
Damien Miller7207f642008-05-19 15:34:50 +1000504 close(err[0]);
505#endif
506
Damien Millerb38eff82000-04-01 11:09:21 +1000507 /* Do processing for the child (exec command etc). */
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000508 do_child(ssh, s, command);
Damien Millerb38eff82000-04-01 11:09:21 +1000509 /* NOTREACHED */
Damien Miller7207f642008-05-19 15:34:50 +1000510 default:
511 break;
Damien Millerb38eff82000-04-01 11:09:21 +1000512 }
Damien Miller7207f642008-05-19 15:34:50 +1000513
Damien Millerbac2d8a2000-09-05 16:13:06 +1100514#ifdef HAVE_CYGWIN
Darren Tucker9d86e5d2009-03-08 11:40:27 +1100515 cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
Damien Millerbac2d8a2000-09-05 16:13:06 +1100516#endif
Damien Miller7207f642008-05-19 15:34:50 +1000517
Damien Millerb38eff82000-04-01 11:09:21 +1000518 s->pid = pid;
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000519 /* Set interactive/non-interactive mode. */
Damien Miller0dac6fb2010-11-20 15:19:38 +1100520 packet_set_interactive(s->display != NULL,
521 options.ip_qos_interactive, options.ip_qos_bulk);
Damien Miller7207f642008-05-19 15:34:50 +1000522
523 /*
524 * Clear loginmsg, since it's the child's responsibility to display
525 * it to the user, otherwise multiple sessions may accumulate
526 * multiple copies of the login messages.
527 */
528 buffer_clear(&loginmsg);
529
Damien Millerb38eff82000-04-01 11:09:21 +1000530#ifdef USE_PIPES
531 /* We are the parent. Close the child sides of the pipes. */
532 close(pin[0]);
533 close(pout[1]);
534 close(perr[1]);
535
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000536 session_set_fds(ssh, s, pin[1], pout[0], perr[0],
markus@openbsd.org6cb6dcf2016-08-13 17:47:40 +0000537 s->is_subsystem, 0);
Damien Miller7207f642008-05-19 15:34:50 +1000538#else
Damien Millerb38eff82000-04-01 11:09:21 +1000539 /* We are the parent. Close the child sides of the socket pairs. */
540 close(inout[0]);
541 close(err[0]);
542
543 /*
544 * Enter the interactive session. Note: server_loop must be able to
545 * handle the case that fdin and fdout are the same.
546 */
markus@openbsd.org6cb6dcf2016-08-13 17:47:40 +0000547 session_set_fds(s, inout[1], inout[1], err[1],
548 s->is_subsystem, 0);
Damien Miller7207f642008-05-19 15:34:50 +1000549#endif
550 return 0;
Damien Millerb38eff82000-04-01 11:09:21 +1000551}
552
553/*
554 * This is called to fork and execute a command when we have a tty. This
555 * will call do_child from the child, and server_loop from the parent after
556 * setting up file descriptors, controlling tty, updating wtmp, utmp,
557 * lastlog, and other such operations.
558 */
Damien Miller7207f642008-05-19 15:34:50 +1000559int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000560do_exec_pty(struct ssh *ssh, Session *s, const char *command)
Damien Millerb38eff82000-04-01 11:09:21 +1000561{
Damien Millerb38eff82000-04-01 11:09:21 +1000562 int fdout, ptyfd, ttyfd, ptymaster;
Damien Millerb38eff82000-04-01 11:09:21 +1000563 pid_t pid;
Damien Millerb38eff82000-04-01 11:09:21 +1000564
565 if (s == NULL)
566 fatal("do_exec_pty: no session");
567 ptyfd = s->ptyfd;
568 ttyfd = s->ttyfd;
569
Damien Miller7207f642008-05-19 15:34:50 +1000570 /*
571 * Create another descriptor of the pty master side for use as the
572 * standard input. We could use the original descriptor, but this
573 * simplifies code in server_loop. The descriptor is bidirectional.
574 * Do this before forking (and cleanup in the child) so as to
575 * detect and gracefully fail out-of-fd conditions.
576 */
577 if ((fdout = dup(ptyfd)) < 0) {
578 error("%s: dup #1: %s", __func__, strerror(errno));
579 close(ttyfd);
580 close(ptyfd);
581 return -1;
582 }
583 /* we keep a reference to the pty master */
584 if ((ptymaster = dup(ptyfd)) < 0) {
585 error("%s: dup #2: %s", __func__, strerror(errno));
586 close(ttyfd);
587 close(ptyfd);
588 close(fdout);
589 return -1;
590 }
591
Damien Millerb38eff82000-04-01 11:09:21 +1000592 /* Fork the child. */
Damien Miller7207f642008-05-19 15:34:50 +1000593 switch ((pid = fork())) {
594 case -1:
595 error("%s: fork: %.100s", __func__, strerror(errno));
596 close(fdout);
597 close(ptymaster);
598 close(ttyfd);
599 close(ptyfd);
600 return -1;
601 case 0:
Darren Tucker3e33cec2003-10-02 16:12:36 +1000602 is_child = 1;
Ben Lindstrombddd5512001-07-04 04:53:53 +0000603
Damien Miller7207f642008-05-19 15:34:50 +1000604 close(fdout);
605 close(ptymaster);
606
Damien Millerb38eff82000-04-01 11:09:21 +1000607 /* Close the master side of the pseudo tty. */
608 close(ptyfd);
609
610 /* Make the pseudo tty our controlling tty. */
611 pty_make_controlling_tty(&ttyfd, s->tty);
612
Damien Miller9c751422001-10-10 15:02:46 +1000613 /* Redirect stdin/stdout/stderr from the pseudo tty. */
614 if (dup2(ttyfd, 0) < 0)
615 error("dup2 stdin: %s", strerror(errno));
616 if (dup2(ttyfd, 1) < 0)
617 error("dup2 stdout: %s", strerror(errno));
618 if (dup2(ttyfd, 2) < 0)
619 error("dup2 stderr: %s", strerror(errno));
Damien Millerb38eff82000-04-01 11:09:21 +1000620
621 /* Close the extra descriptor for the pseudo tty. */
622 close(ttyfd);
623
Damien Miller942da032000-08-18 13:59:06 +1000624 /* record login, etc. similar to login(1) */
otto@openbsd.orgfc041c42016-08-23 16:21:45 +0000625#ifndef HAVE_OSF_SIA
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000626 do_login(ssh, s, command);
Damien Miller364a9bd2001-04-16 18:37:05 +1000627#endif
Damien Miller7207f642008-05-19 15:34:50 +1000628 /*
629 * Do common processing for the child, such as execing
630 * the command.
631 */
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000632 do_child(ssh, s, command);
Darren Tucker43e7a352009-06-21 19:50:08 +1000633 /* NOTREACHED */
Damien Miller7207f642008-05-19 15:34:50 +1000634 default:
635 break;
Damien Millerb38eff82000-04-01 11:09:21 +1000636 }
Damien Miller7207f642008-05-19 15:34:50 +1000637
Damien Millerbac2d8a2000-09-05 16:13:06 +1100638#ifdef HAVE_CYGWIN
Darren Tucker9d86e5d2009-03-08 11:40:27 +1100639 cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
Damien Millerbac2d8a2000-09-05 16:13:06 +1100640#endif
Damien Miller7207f642008-05-19 15:34:50 +1000641
Damien Millerb38eff82000-04-01 11:09:21 +1000642 s->pid = pid;
643
644 /* Parent. Close the slave side of the pseudo tty. */
645 close(ttyfd);
646
Damien Millerb38eff82000-04-01 11:09:21 +1000647 /* Enter interactive session. */
Damien Miller7207f642008-05-19 15:34:50 +1000648 s->ptymaster = ptymaster;
Damien Miller0dac6fb2010-11-20 15:19:38 +1100649 packet_set_interactive(1,
650 options.ip_qos_interactive, options.ip_qos_bulk);
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000651 session_set_fds(ssh, s, ptyfd, fdout, -1, 1, 1);
Damien Miller7207f642008-05-19 15:34:50 +1000652 return 0;
Damien Millerb38eff82000-04-01 11:09:21 +1000653}
654
Ben Lindstrom97c677d2001-05-08 20:33:05 +0000655#ifdef LOGIN_NEEDS_UTMPX
Damien Miller599d8eb2001-09-15 12:25:53 +1000656static void
Ben Lindstrom97c677d2001-05-08 20:33:05 +0000657do_pre_login(Session *s)
658{
Darren Tuckeraa377682016-06-20 15:55:34 +1000659 struct ssh *ssh = active_state; /* XXX */
Ben Lindstrom97c677d2001-05-08 20:33:05 +0000660 socklen_t fromlen;
661 struct sockaddr_storage from;
662 pid_t pid = getpid();
663
664 /*
665 * Get IP address of client. If the connection is not a socket, let
666 * the address be 0.0.0.0.
667 */
668 memset(&from, 0, sizeof(from));
Damien Millerebc23062002-09-04 16:45:09 +1000669 fromlen = sizeof(from);
Ben Lindstrom97c677d2001-05-08 20:33:05 +0000670 if (packet_connection_is_on_socket()) {
Ben Lindstrom97c677d2001-05-08 20:33:05 +0000671 if (getpeername(packet_get_connection_in(),
Damien Miller90967402006-03-26 14:07:26 +1100672 (struct sockaddr *)&from, &fromlen) < 0) {
Ben Lindstrom97c677d2001-05-08 20:33:05 +0000673 debug("getpeername: %.100s", strerror(errno));
Darren Tucker3e33cec2003-10-02 16:12:36 +1000674 cleanup_exit(255);
Ben Lindstrom97c677d2001-05-08 20:33:05 +0000675 }
676 }
677
678 record_utmp_only(pid, s->tty, s->pw->pw_name,
Darren Tuckeraa377682016-06-20 15:55:34 +1000679 session_get_remote_name_or_ip(ssh, utmp_len, options.use_dns),
Kevin Steves678ee512003-01-01 23:43:55 +0000680 (struct sockaddr *)&from, fromlen);
Ben Lindstrom97c677d2001-05-08 20:33:05 +0000681}
682#endif
683
Ben Lindstromc85ab8a2001-06-21 03:13:10 +0000684/*
685 * This is called to fork and execute a command. If another command is
686 * to be forced, execute that instead.
687 */
Damien Miller7207f642008-05-19 15:34:50 +1000688int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000689do_exec(struct ssh *ssh, Session *s, const char *command)
Ben Lindstromc85ab8a2001-06-21 03:13:10 +0000690{
Damien Miller7207f642008-05-19 15:34:50 +1000691 int ret;
djm@openbsd.org5a0fcb72016-02-16 03:37:48 +0000692 const char *forced = NULL, *tty = NULL;
693 char session_type[1024];
Damien Miller7207f642008-05-19 15:34:50 +1000694
Damien Millere2754432006-07-24 14:06:47 +1000695 if (options.adm_forced_command) {
696 original_command = command;
697 command = options.adm_forced_command;
Damien Miller71df7522013-10-15 12:12:02 +1100698 forced = "(config)";
djm@openbsd.org7c856852018-03-03 03:15:51 +0000699 } else if (auth_opts->force_command != NULL) {
Ben Lindstromc85ab8a2001-06-21 03:13:10 +0000700 original_command = command;
djm@openbsd.org7c856852018-03-03 03:15:51 +0000701 command = auth_opts->force_command;
Damien Miller71df7522013-10-15 12:12:02 +1100702 forced = "(key-option)";
703 }
704 if (forced != NULL) {
Darren Tuckerd6b06a92010-01-08 17:09:11 +1100705 if (IS_INTERNAL_SFTP(command)) {
706 s->is_subsystem = s->is_subsystem ?
707 SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR;
708 } else if (s->is_subsystem)
Damien Millerdfc24252008-02-10 22:29:40 +1100709 s->is_subsystem = SUBSYSTEM_EXT;
Damien Miller71df7522013-10-15 12:12:02 +1100710 snprintf(session_type, sizeof(session_type),
711 "forced-command %s '%.900s'", forced, command);
712 } else if (s->is_subsystem) {
713 snprintf(session_type, sizeof(session_type),
714 "subsystem '%.900s'", s->subsys);
715 } else if (command == NULL) {
716 snprintf(session_type, sizeof(session_type), "shell");
717 } else {
718 /* NB. we don't log unforced commands to preserve privacy */
719 snprintf(session_type, sizeof(session_type), "command");
Ben Lindstromc85ab8a2001-06-21 03:13:10 +0000720 }
721
Damien Miller71df7522013-10-15 12:12:02 +1100722 if (s->ttyfd != -1) {
723 tty = s->tty;
724 if (strncmp(tty, "/dev/", 5) == 0)
725 tty += 5;
726 }
727
djm@openbsd.org5a0fcb72016-02-16 03:37:48 +0000728 verbose("Starting session: %s%s%s for %s from %.200s port %d id %d",
Damien Miller71df7522013-10-15 12:12:02 +1100729 session_type,
730 tty == NULL ? "" : " on ",
731 tty == NULL ? "" : tty,
732 s->pw->pw_name,
djm@openbsd.org95767262016-03-07 19:02:43 +0000733 ssh_remote_ipaddr(ssh),
734 ssh_remote_port(ssh),
djm@openbsd.org5a0fcb72016-02-16 03:37:48 +0000735 s->self);
Damien Miller71df7522013-10-15 12:12:02 +1100736
Darren Tucker2e0cf0d2005-02-08 21:52:47 +1100737#ifdef SSH_AUDIT_EVENTS
Darren Tucker269a1ea2005-02-03 00:20:53 +1100738 if (command != NULL)
739 PRIVSEP(audit_run_command(command));
740 else if (s->ttyfd == -1) {
741 char *shell = s->pw->pw_shell;
742
743 if (shell[0] == '\0') /* empty shell means /bin/sh */
744 shell =_PATH_BSHELL;
745 PRIVSEP(audit_run_command(shell));
746 }
747#endif
Ben Lindstromc85ab8a2001-06-21 03:13:10 +0000748 if (s->ttyfd != -1)
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000749 ret = do_exec_pty(ssh, s, command);
Ben Lindstromc85ab8a2001-06-21 03:13:10 +0000750 else
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000751 ret = do_exec_no_pty(ssh, s, command);
Ben Lindstromc85ab8a2001-06-21 03:13:10 +0000752
Ben Lindstrom0a7ca6c2001-06-21 03:17:42 +0000753 original_command = NULL;
Ben Lindstromc85ab8a2001-06-21 03:13:10 +0000754
Darren Tucker09991742004-07-17 17:05:14 +1000755 /*
756 * Clear loginmsg: it's the child's responsibility to display
757 * it to the user, otherwise multiple sessions may accumulate
758 * multiple copies of the login messages.
759 */
760 buffer_clear(&loginmsg);
Damien Miller7207f642008-05-19 15:34:50 +1000761
762 return ret;
Darren Tucker09991742004-07-17 17:05:14 +1000763}
Ben Lindstrom4e97e852002-02-19 21:50:43 +0000764
Damien Miller942da032000-08-18 13:59:06 +1000765/* administrative, login(1)-like work */
766void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +0000767do_login(struct ssh *ssh, Session *s, const char *command)
Damien Miller942da032000-08-18 13:59:06 +1000768{
Damien Miller942da032000-08-18 13:59:06 +1000769 socklen_t fromlen;
770 struct sockaddr_storage from;
Damien Miller942da032000-08-18 13:59:06 +1000771 struct passwd * pw = s->pw;
772 pid_t pid = getpid();
773
774 /*
775 * Get IP address of client. If the connection is not a socket, let
776 * the address be 0.0.0.0.
777 */
778 memset(&from, 0, sizeof(from));
Kevin Steves678ee512003-01-01 23:43:55 +0000779 fromlen = sizeof(from);
Damien Miller942da032000-08-18 13:59:06 +1000780 if (packet_connection_is_on_socket()) {
Damien Miller942da032000-08-18 13:59:06 +1000781 if (getpeername(packet_get_connection_in(),
Darren Tucker43e7a352009-06-21 19:50:08 +1000782 (struct sockaddr *)&from, &fromlen) < 0) {
Damien Miller942da032000-08-18 13:59:06 +1000783 debug("getpeername: %.100s", strerror(errno));
Darren Tucker3e33cec2003-10-02 16:12:36 +1000784 cleanup_exit(255);
Damien Miller942da032000-08-18 13:59:06 +1000785 }
786 }
787
788 /* Record that there was a login on that tty from the remote host. */
Ben Lindstrom2bf56e22002-04-02 20:32:46 +0000789 if (!use_privsep)
790 record_login(pid, s->tty, pw->pw_name, pw->pw_uid,
djm@openbsd.org95767262016-03-07 19:02:43 +0000791 session_get_remote_name_or_ip(ssh, utmp_len,
Damien Miller3a961dc2003-06-03 10:25:48 +1000792 options.use_dns),
Damien Millerebc23062002-09-04 16:45:09 +1000793 (struct sockaddr *)&from, fromlen);
Damien Miller942da032000-08-18 13:59:06 +1000794
Kevin Steves092f2ef2000-10-14 13:36:13 +0000795#ifdef USE_PAM
796 /*
797 * If password change is needed, do it now.
798 * This needs to occur before the ~/.hushlogin check.
799 */
Darren Tucker1921ed92004-02-10 13:23:28 +1100800 if (options.use_pam && !use_privsep && s->authctxt->force_pwchange) {
801 display_loginmsg();
Kevin Steves092f2ef2000-10-14 13:36:13 +0000802 do_pam_chauthtok();
Darren Tucker1921ed92004-02-10 13:23:28 +1100803 s->authctxt->force_pwchange = 0;
Damien Miller1f499fd2003-08-25 13:08:49 +1000804 /* XXX - signal [net] parent to enable forwardings */
Kevin Steves092f2ef2000-10-14 13:36:13 +0000805 }
806#endif
807
Damien Millercf205e82001-04-16 18:29:15 +1000808 if (check_quietlogin(s, command))
Damien Miller942da032000-08-18 13:59:06 +1000809 return;
810
Darren Tucker1921ed92004-02-10 13:23:28 +1100811 display_loginmsg();
Damien Miller942da032000-08-18 13:59:06 +1000812
Damien Millercf205e82001-04-16 18:29:15 +1000813 do_motd();
814}
815
816/*
817 * Display the message of the day.
818 */
819void
820do_motd(void)
821{
822 FILE *f;
823 char buf[256];
824
Damien Miller942da032000-08-18 13:59:06 +1000825 if (options.print_motd) {
Damien Millerad833b32000-08-23 10:46:23 +1000826#ifdef HAVE_LOGIN_CAP
827 f = fopen(login_getcapstr(lc, "welcome", "/etc/motd",
828 "/etc/motd"), "r");
829#else
Damien Miller942da032000-08-18 13:59:06 +1000830 f = fopen("/etc/motd", "r");
Damien Millerad833b32000-08-23 10:46:23 +1000831#endif
Damien Miller942da032000-08-18 13:59:06 +1000832 if (f) {
833 while (fgets(buf, sizeof(buf), f))
834 fputs(buf, stdout);
835 fclose(f);
836 }
837 }
838}
839
Kevin Steves8f63caa2001-07-04 18:23:02 +0000840
841/*
842 * Check for quiet login, either .hushlogin or command given.
843 */
844int
845check_quietlogin(Session *s, const char *command)
846{
847 char buf[256];
848 struct passwd *pw = s->pw;
849 struct stat st;
850
851 /* Return 1 if .hushlogin exists or a command given. */
852 if (command != NULL)
853 return 1;
854 snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir);
855#ifdef HAVE_LOGIN_CAP
856 if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0)
857 return 1;
858#else
859 if (stat(buf, &st) >= 0)
860 return 1;
861#endif
862 return 0;
863}
864
Damien Millerb38eff82000-04-01 11:09:21 +1000865/*
Damien Millerb38eff82000-04-01 11:09:21 +1000866 * Reads environment variables from the given file and adds/overrides them
867 * into the environment. If the file does not exist, this does nothing.
868 * Otherwise, it must consist of empty lines, comments (line starts with '#')
869 * and assignments of the form name=value. No other forms are allowed.
djm@openbsd.org95344c22018-07-03 10:59:35 +0000870 * If whitelist is not NULL, then it is interpreted as a pattern list and
871 * only variable names that match it will be accepted.
Damien Millerb38eff82000-04-01 11:09:21 +1000872 */
Ben Lindstrombba81212001-06-25 05:01:22 +0000873static void
Ben Lindstrom46c16222000-12-22 01:43:59 +0000874read_environment_file(char ***env, u_int *envsize,
djm@openbsd.org95344c22018-07-03 10:59:35 +0000875 const char *filename, const char *whitelist)
Damien Millerb38eff82000-04-01 11:09:21 +1000876{
877 FILE *f;
markus@openbsd.org7f906352018-06-06 18:29:18 +0000878 char *line = NULL, *cp, *value;
879 size_t linesize = 0;
Damien Miller990070a2002-06-26 23:51:06 +1000880 u_int lineno = 0;
Damien Millerb38eff82000-04-01 11:09:21 +1000881
882 f = fopen(filename, "r");
883 if (!f)
884 return;
885
markus@openbsd.org7f906352018-06-06 18:29:18 +0000886 while (getline(&line, &linesize, f) != -1) {
Damien Miller990070a2002-06-26 23:51:06 +1000887 if (++lineno > 1000)
888 fatal("Too many lines in environment file %s", filename);
markus@openbsd.org7f906352018-06-06 18:29:18 +0000889 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
Damien Millerb38eff82000-04-01 11:09:21 +1000890 ;
891 if (!*cp || *cp == '#' || *cp == '\n')
892 continue;
Damien Miller14b017d2007-09-17 16:09:15 +1000893
894 cp[strcspn(cp, "\n")] = '\0';
895
Damien Millerb38eff82000-04-01 11:09:21 +1000896 value = strchr(cp, '=');
897 if (value == NULL) {
Damien Miller990070a2002-06-26 23:51:06 +1000898 fprintf(stderr, "Bad line %u in %.100s\n", lineno,
899 filename);
Damien Millerb38eff82000-04-01 11:09:21 +1000900 continue;
901 }
Damien Millerb1715dc2000-05-30 13:44:51 +1000902 /*
903 * Replace the equals sign by nul, and advance value to
904 * the value string.
905 */
Damien Millerb38eff82000-04-01 11:09:21 +1000906 *value = '\0';
907 value++;
djm@openbsd.org95344c22018-07-03 10:59:35 +0000908 if (whitelist != NULL &&
909 match_pattern_list(cp, whitelist, 0) != 1)
910 continue;
Damien Millerb38eff82000-04-01 11:09:21 +1000911 child_set_env(env, envsize, cp, value);
912 }
markus@openbsd.org7f906352018-06-06 18:29:18 +0000913 free(line);
Damien Millerb38eff82000-04-01 11:09:21 +1000914 fclose(f);
915}
916
Darren Tuckere1a790d2003-09-16 11:52:19 +1000917#ifdef HAVE_ETC_DEFAULT_LOGIN
918/*
919 * Return named variable from specified environment, or NULL if not present.
920 */
921static char *
922child_get_env(char **env, const char *name)
923{
924 int i;
925 size_t len;
926
927 len = strlen(name);
928 for (i=0; env[i] != NULL; i++)
929 if (strncmp(name, env[i], len) == 0 && env[i][len] == '=')
930 return(env[i] + len + 1);
931 return NULL;
932}
933
934/*
935 * Read /etc/default/login.
936 * We pick up the PATH (or SUPATH for root) and UMASK.
937 */
938static void
939read_etc_default_login(char ***env, u_int *envsize, uid_t uid)
940{
941 char **tmpenv = NULL, *var;
Darren Tuckerc11b1e82003-09-19 20:56:51 +1000942 u_int i, tmpenvsize = 0;
Darren Tuckerf391ba62003-10-02 20:07:09 +1000943 u_long mask;
Darren Tuckere1a790d2003-09-16 11:52:19 +1000944
945 /*
946 * We don't want to copy the whole file to the child's environment,
947 * so we use a temporary environment and copy the variables we're
948 * interested in.
949 */
950 read_environment_file(&tmpenv, &tmpenvsize, "/etc/default/login");
951
Darren Tuckerc11b1e82003-09-19 20:56:51 +1000952 if (tmpenv == NULL)
953 return;
954
Darren Tuckere1a790d2003-09-16 11:52:19 +1000955 if (uid == 0)
956 var = child_get_env(tmpenv, "SUPATH");
957 else
958 var = child_get_env(tmpenv, "PATH");
959 if (var != NULL)
960 child_set_env(env, envsize, "PATH", var);
Damien Miller787b2ec2003-11-21 23:56:47 +1100961
Darren Tuckere1a790d2003-09-16 11:52:19 +1000962 if ((var = child_get_env(tmpenv, "UMASK")) != NULL)
963 if (sscanf(var, "%5lo", &mask) == 1)
Darren Tuckerf391ba62003-10-02 20:07:09 +1000964 umask((mode_t)mask);
Damien Miller787b2ec2003-11-21 23:56:47 +1100965
Darren Tuckere1a790d2003-09-16 11:52:19 +1000966 for (i = 0; tmpenv[i] != NULL; i++)
Darren Tuckerf60845f2013-06-02 08:07:31 +1000967 free(tmpenv[i]);
968 free(tmpenv);
Darren Tuckere1a790d2003-09-16 11:52:19 +1000969}
970#endif /* HAVE_ETC_DEFAULT_LOGIN */
971
Damien Miller94bc1e72017-07-28 14:50:59 +1000972static void
973copy_environment_blacklist(char **source, char ***env, u_int *envsize,
974 const char *blacklist)
Damien Millerb38eff82000-04-01 11:09:21 +1000975{
Damien Millerbb9ffc12002-01-08 10:59:32 +1100976 char *var_name, *var_val;
Damien Millerb38eff82000-04-01 11:09:21 +1000977 int i;
978
Damien Millerbb9ffc12002-01-08 10:59:32 +1100979 if (source == NULL)
Damien Millerb38eff82000-04-01 11:09:21 +1000980 return;
Kevin Stevesef4eea92001-02-05 12:42:17 +0000981
Damien Millerbb9ffc12002-01-08 10:59:32 +1100982 for(i = 0; source[i] != NULL; i++) {
983 var_name = xstrdup(source[i]);
984 if ((var_val = strstr(var_name, "=")) == NULL) {
Darren Tuckerf60845f2013-06-02 08:07:31 +1000985 free(var_name);
Damien Millerb38eff82000-04-01 11:09:21 +1000986 continue;
Damien Millerb38eff82000-04-01 11:09:21 +1000987 }
Damien Millerbb9ffc12002-01-08 10:59:32 +1100988 *var_val++ = '\0';
989
Damien Miller94bc1e72017-07-28 14:50:59 +1000990 if (blacklist == NULL ||
991 match_pattern_list(var_name, blacklist, 0) != 1) {
992 debug3("Copy environment: %s=%s", var_name, var_val);
993 child_set_env(env, envsize, var_name, var_val);
994 }
Damien Miller787b2ec2003-11-21 23:56:47 +1100995
Darren Tuckerf60845f2013-06-02 08:07:31 +1000996 free(var_name);
Damien Millerb38eff82000-04-01 11:09:21 +1000997 }
998}
Damien Millercb5e44a2000-09-29 12:12:36 +1100999
Damien Miller94bc1e72017-07-28 14:50:59 +10001000void
1001copy_environment(char **source, char ***env, u_int *envsize)
1002{
1003 copy_environment_blacklist(source, env, envsize, NULL);
1004}
1005
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001006static char **
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001007do_setup_env(struct ssh *ssh, Session *s, const char *shell)
Damien Millerb38eff82000-04-01 11:09:21 +10001008{
Damien Millerb38eff82000-04-01 11:09:21 +10001009 char buf[256];
djm@openbsd.org7c856852018-03-03 03:15:51 +00001010 size_t n;
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001011 u_int i, envsize;
djm@openbsd.org28013752018-06-09 03:03:10 +00001012 char *ocp, *cp, *value, **env, *laddr;
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001013 struct passwd *pw = s->pw;
Darren Tucker9d86e5d2009-03-08 11:40:27 +11001014#if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN)
Damien Millerad5ecbf2006-07-24 15:03:06 +10001015 char *path = NULL;
1016#endif
Damien Millerb38eff82000-04-01 11:09:21 +10001017
Damien Millerb38eff82000-04-01 11:09:21 +10001018 /* Initialize the environment. */
1019 envsize = 100;
Darren Tuckerd8093e42006-05-04 16:24:34 +10001020 env = xcalloc(envsize, sizeof(char *));
Damien Millerb38eff82000-04-01 11:09:21 +10001021 env[0] = NULL;
1022
Damien Millerbac2d8a2000-09-05 16:13:06 +11001023#ifdef HAVE_CYGWIN
1024 /*
1025 * The Windows environment contains some setting which are
1026 * important for a running system. They must not be dropped.
1027 */
Darren Tucker14c372d2004-08-30 20:42:08 +10001028 {
1029 char **p;
1030
1031 p = fetch_windows_environment();
1032 copy_environment(p, &env, &envsize);
1033 free_windows_environment(p);
1034 }
Damien Millerbac2d8a2000-09-05 16:13:06 +11001035#endif
1036
Darren Tucker0efd1552003-08-26 11:49:55 +10001037#ifdef GSSAPI
Damien Millera8e06ce2003-11-21 23:48:55 +11001038 /* Allow any GSSAPI methods that we've used to alter
Darren Tucker0efd1552003-08-26 11:49:55 +10001039 * the childs environment as they see fit
1040 */
1041 ssh_gssapi_do_child(&env, &envsize);
1042#endif
1043
djm@openbsd.org83b58182016-08-19 03:18:06 +00001044 /* Set basic environment. */
1045 for (i = 0; i < s->num_env; i++)
1046 child_set_env(&env, &envsize, s->env[i].name, s->env[i].val);
Darren Tucker46bc0752004-05-02 22:11:30 +10001047
djm@openbsd.org83b58182016-08-19 03:18:06 +00001048 child_set_env(&env, &envsize, "USER", pw->pw_name);
1049 child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
Damien Millerdfedbf82003-01-03 14:52:53 +11001050#ifdef _AIX
djm@openbsd.org83b58182016-08-19 03:18:06 +00001051 child_set_env(&env, &envsize, "LOGIN", pw->pw_name);
Damien Millerdfedbf82003-01-03 14:52:53 +11001052#endif
djm@openbsd.org83b58182016-08-19 03:18:06 +00001053 child_set_env(&env, &envsize, "HOME", pw->pw_dir);
Damien Millerad833b32000-08-23 10:46:23 +10001054#ifdef HAVE_LOGIN_CAP
djm@openbsd.org83b58182016-08-19 03:18:06 +00001055 if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETPATH) < 0)
1056 child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
1057 else
1058 child_set_env(&env, &envsize, "PATH", getenv("PATH"));
Damien Millercb5e44a2000-09-29 12:12:36 +11001059#else /* HAVE_LOGIN_CAP */
1060# ifndef HAVE_CYGWIN
djm@openbsd.org83b58182016-08-19 03:18:06 +00001061 /*
1062 * There's no standard path on Windows. The path contains
1063 * important components pointing to the system directories,
1064 * needed for loading shared libraries. So the path better
1065 * remains intact here.
1066 */
Darren Tuckere1a790d2003-09-16 11:52:19 +10001067# ifdef HAVE_ETC_DEFAULT_LOGIN
djm@openbsd.org83b58182016-08-19 03:18:06 +00001068 read_etc_default_login(&env, &envsize, pw->pw_uid);
1069 path = child_get_env(env, "PATH");
Darren Tuckere1a790d2003-09-16 11:52:19 +10001070# endif /* HAVE_ETC_DEFAULT_LOGIN */
djm@openbsd.org83b58182016-08-19 03:18:06 +00001071 if (path == NULL || *path == '\0') {
1072 child_set_env(&env, &envsize, "PATH",
1073 s->pw->pw_uid == 0 ? SUPERUSER_PATH : _PATH_STDPATH);
1074 }
Damien Millercb5e44a2000-09-29 12:12:36 +11001075# endif /* HAVE_CYGWIN */
1076#endif /* HAVE_LOGIN_CAP */
Damien Millerb38eff82000-04-01 11:09:21 +10001077
djm@openbsd.org83b58182016-08-19 03:18:06 +00001078 snprintf(buf, sizeof buf, "%.200s/%.50s", _PATH_MAILDIR, pw->pw_name);
1079 child_set_env(&env, &envsize, "MAIL", buf);
Damien Millerb38eff82000-04-01 11:09:21 +10001080
djm@openbsd.org83b58182016-08-19 03:18:06 +00001081 /* Normal systems set SHELL by default. */
1082 child_set_env(&env, &envsize, "SHELL", shell);
1083
Damien Millerb38eff82000-04-01 11:09:21 +10001084 if (getenv("TZ"))
1085 child_set_env(&env, &envsize, "TZ", getenv("TZ"));
Ben Lindstrom86fe8682001-03-17 00:32:57 +00001086 if (s->term)
1087 child_set_env(&env, &envsize, "TERM", s->term);
1088 if (s->display)
1089 child_set_env(&env, &envsize, "DISPLAY", s->display);
Damien Millerb38eff82000-04-01 11:09:21 +10001090
Darren Tucker9dc6c7d2005-02-02 18:30:33 +11001091 /*
1092 * Since we clear KRB5CCNAME at startup, if it's set now then it
1093 * must have been set by a native authentication method (eg AIX or
1094 * SIA), so copy it to the child.
1095 */
1096 {
1097 char *cp;
1098
1099 if ((cp = getenv("KRB5CCNAME")) != NULL)
1100 child_set_env(&env, &envsize, "KRB5CCNAME", cp);
1101 }
1102
Damien Millerb38eff82000-04-01 11:09:21 +10001103#ifdef _AIX
Ben Lindstrom839ac4f2002-02-24 20:42:46 +00001104 {
1105 char *cp;
1106
1107 if ((cp = getenv("AUTHSTATE")) != NULL)
1108 child_set_env(&env, &envsize, "AUTHSTATE", cp);
Ben Lindstrom839ac4f2002-02-24 20:42:46 +00001109 read_environment_file(&env, &envsize, "/etc/environment");
1110 }
Damien Millerb38eff82000-04-01 11:09:21 +10001111#endif
Ben Lindstromec95ed92001-07-04 04:21:14 +00001112#ifdef KRB5
Damien Miller9c870f92004-04-16 22:47:55 +10001113 if (s->authctxt->krb5_ccname)
Ben Lindstromec95ed92001-07-04 04:21:14 +00001114 child_set_env(&env, &envsize, "KRB5CCNAME",
Damien Miller9c870f92004-04-16 22:47:55 +10001115 s->authctxt->krb5_ccname);
Ben Lindstromec95ed92001-07-04 04:21:14 +00001116#endif
djm@openbsd.org3b9798b2018-06-09 02:58:02 +00001117 if (auth_sock_name != NULL)
1118 child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
1119 auth_sock_name);
1120
1121
1122 /* Set custom environment options from pubkey authentication. */
1123 if (options.permit_user_env) {
1124 for (n = 0 ; n < auth_opts->nenv; n++) {
1125 ocp = xstrdup(auth_opts->env[n]);
1126 cp = strchr(ocp, '=');
1127 if (*cp == '=') {
1128 *cp = '\0';
djm@openbsd.org95344c22018-07-03 10:59:35 +00001129 /* Apply PermitUserEnvironment whitelist */
1130 if (options.permit_user_env_whitelist == NULL ||
1131 match_pattern_list(ocp,
1132 options.permit_user_env_whitelist, 0) == 1)
1133 child_set_env(&env, &envsize,
1134 ocp, cp + 1);
djm@openbsd.org3b9798b2018-06-09 02:58:02 +00001135 }
1136 free(ocp);
1137 }
1138 }
1139
1140 /* read $HOME/.ssh/environment. */
1141 if (options.permit_user_env) {
1142 snprintf(buf, sizeof buf, "%.200s/.ssh/environment",
1143 pw->pw_dir);
djm@openbsd.org95344c22018-07-03 10:59:35 +00001144 read_environment_file(&env, &envsize, buf,
1145 options.permit_user_env_whitelist);
djm@openbsd.org3b9798b2018-06-09 02:58:02 +00001146 }
1147
Damien Millerb38eff82000-04-01 11:09:21 +10001148#ifdef USE_PAM
Kevin Steves38b050a2002-07-23 00:44:07 +00001149 /*
1150 * Pull in any environment variables that may have
1151 * been set by PAM.
1152 */
djm@openbsd.org83b58182016-08-19 03:18:06 +00001153 if (options.use_pam) {
Damien Millerc756e9b2003-11-17 21:41:42 +11001154 char **p;
Damien Miller787b2ec2003-11-21 23:56:47 +11001155
Damien Miller94bc1e72017-07-28 14:50:59 +10001156 /*
1157 * Don't allow SSH_AUTH_INFO variables posted to PAM to leak
1158 * back into the environment.
1159 */
Damien Millerc756e9b2003-11-17 21:41:42 +11001160 p = fetch_pam_child_environment();
Damien Miller94bc1e72017-07-28 14:50:59 +10001161 copy_environment_blacklist(p, &env, &envsize, "SSH_AUTH_INFO*");
Damien Millerc756e9b2003-11-17 21:41:42 +11001162 free_pam_environment(p);
Kevin Steves38b050a2002-07-23 00:44:07 +00001163
Damien Millerc756e9b2003-11-17 21:41:42 +11001164 p = fetch_pam_environment();
Damien Miller94bc1e72017-07-28 14:50:59 +10001165 copy_environment_blacklist(p, &env, &envsize, "SSH_AUTH_INFO*");
Kevin Steves38b050a2002-07-23 00:44:07 +00001166 free_pam_environment(p);
1167 }
Damien Millerb38eff82000-04-01 11:09:21 +10001168#endif /* USE_PAM */
1169
djm@openbsd.org28013752018-06-09 03:03:10 +00001170 /* Environment specified by admin */
1171 for (i = 0; i < options.num_setenv; i++) {
1172 cp = xstrdup(options.setenv[i]);
1173 if ((value = strchr(cp, '=')) == NULL) {
1174 /* shouldn't happen; vars are checked in servconf.c */
1175 fatal("Invalid config SetEnv: %s", options.setenv[i]);
1176 }
1177 *value++ = '\0';
1178 child_set_env(&env, &envsize, cp, value);
1179 }
1180
djm@openbsd.org3b9798b2018-06-09 02:58:02 +00001181 /* SSH_CLIENT deprecated */
1182 snprintf(buf, sizeof buf, "%.50s %d %d",
1183 ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
1184 ssh_local_port(ssh));
1185 child_set_env(&env, &envsize, "SSH_CLIENT", buf);
Damien Millerb38eff82000-04-01 11:09:21 +10001186
djm@openbsd.org3b9798b2018-06-09 02:58:02 +00001187 laddr = get_local_ipaddr(packet_get_connection_in());
1188 snprintf(buf, sizeof buf, "%.50s %d %.50s %d",
1189 ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
1190 laddr, ssh_local_port(ssh));
1191 free(laddr);
1192 child_set_env(&env, &envsize, "SSH_CONNECTION", buf);
1193
1194 if (tun_fwd_ifnames != NULL)
1195 child_set_env(&env, &envsize, "SSH_TUNNEL", tun_fwd_ifnames);
1196 if (auth_info_file != NULL)
1197 child_set_env(&env, &envsize, "SSH_USER_AUTH", auth_info_file);
1198 if (s->ttyfd != -1)
1199 child_set_env(&env, &envsize, "SSH_TTY", s->tty);
1200 if (original_command)
1201 child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND",
1202 original_command);
1203
Damien Millerb38eff82000-04-01 11:09:21 +10001204 if (debug_flag) {
1205 /* dump the environment */
1206 fprintf(stderr, "Environment:\n");
1207 for (i = 0; env[i]; i++)
1208 fprintf(stderr, " %.200s\n", env[i]);
1209 }
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001210 return env;
1211}
1212
1213/*
1214 * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found
1215 * first in this order).
1216 */
1217static void
djm@openbsd.org7c856852018-03-03 03:15:51 +00001218do_rc_files(struct ssh *ssh, Session *s, const char *shell)
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001219{
1220 FILE *f = NULL;
1221 char cmd[1024];
1222 int do_xauth;
1223 struct stat st;
1224
1225 do_xauth =
1226 s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL;
1227
Damien Millera1b48cc2008-03-27 11:02:02 +11001228 /* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */
Damien Miller55360e12008-03-27 11:02:27 +11001229 if (!s->is_subsystem && options.adm_forced_command == NULL &&
djm@openbsd.org7c856852018-03-03 03:15:51 +00001230 auth_opts->permit_user_rc && options.permit_user_rc &&
Damien Miller72e6b5c2014-07-04 09:00:04 +10001231 stat(_PATH_SSH_USER_RC, &st) >= 0) {
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001232 snprintf(cmd, sizeof cmd, "%s -c '%s %s'",
1233 shell, _PATH_BSHELL, _PATH_SSH_USER_RC);
1234 if (debug_flag)
1235 fprintf(stderr, "Running %s\n", cmd);
1236 f = popen(cmd, "w");
1237 if (f) {
1238 if (do_xauth)
1239 fprintf(f, "%s %s\n", s->auth_proto,
1240 s->auth_data);
1241 pclose(f);
1242 } else
1243 fprintf(stderr, "Could not run %s\n",
1244 _PATH_SSH_USER_RC);
1245 } else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) {
1246 if (debug_flag)
1247 fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,
1248 _PATH_SSH_SYSTEM_RC);
1249 f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w");
1250 if (f) {
1251 if (do_xauth)
1252 fprintf(f, "%s %s\n", s->auth_proto,
1253 s->auth_data);
1254 pclose(f);
1255 } else
1256 fprintf(stderr, "Could not run %s\n",
1257 _PATH_SSH_SYSTEM_RC);
1258 } else if (do_xauth && options.xauth_location != NULL) {
1259 /* Add authority data to .Xauthority if appropriate. */
1260 if (debug_flag) {
1261 fprintf(stderr,
Ben Lindstrom611797e2002-12-23 02:15:57 +00001262 "Running %.500s remove %.100s\n",
Darren Tucker3e33cec2003-10-02 16:12:36 +10001263 options.xauth_location, s->auth_display);
Ben Lindstrom611797e2002-12-23 02:15:57 +00001264 fprintf(stderr,
1265 "%.500s add %.100s %.100s %.100s\n",
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001266 options.xauth_location, s->auth_display,
1267 s->auth_proto, s->auth_data);
1268 }
1269 snprintf(cmd, sizeof cmd, "%s -q -",
1270 options.xauth_location);
1271 f = popen(cmd, "w");
1272 if (f) {
Ben Lindstrom611797e2002-12-23 02:15:57 +00001273 fprintf(f, "remove %s\n",
1274 s->auth_display);
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001275 fprintf(f, "add %s %s %s\n",
1276 s->auth_display, s->auth_proto,
1277 s->auth_data);
1278 pclose(f);
1279 } else {
1280 fprintf(stderr, "Could not run %s\n",
1281 cmd);
1282 }
1283 }
1284}
1285
1286static void
1287do_nologin(struct passwd *pw)
1288{
1289 FILE *f = NULL;
Darren Tucker09aa4c02010-01-12 19:51:48 +11001290 char buf[1024], *nl, *def_nl = _PATH_NOLOGIN;
1291 struct stat sb;
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001292
1293#ifdef HAVE_LOGIN_CAP
Damien Miller29cd1882012-04-22 11:08:10 +10001294 if (login_getcapbool(lc, "ignorenologin", 0) || pw->pw_uid == 0)
Darren Tucker09aa4c02010-01-12 19:51:48 +11001295 return;
1296 nl = login_getcapstr(lc, "nologin", def_nl, def_nl);
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001297#else
Darren Tucker09aa4c02010-01-12 19:51:48 +11001298 if (pw->pw_uid == 0)
1299 return;
1300 nl = def_nl;
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001301#endif
Darren Tucker09aa4c02010-01-12 19:51:48 +11001302 if (stat(nl, &sb) == -1) {
1303 if (nl != def_nl)
Darren Tuckera627d422013-06-02 07:31:17 +10001304 free(nl);
Darren Tucker09aa4c02010-01-12 19:51:48 +11001305 return;
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001306 }
Darren Tucker09aa4c02010-01-12 19:51:48 +11001307
1308 /* /etc/nologin exists. Print its contents if we can and exit. */
1309 logit("User %.100s not allowed because %s exists", pw->pw_name, nl);
1310 if ((f = fopen(nl, "r")) != NULL) {
Darren Tucker19edfd42018-02-13 08:25:46 +11001311 while (fgets(buf, sizeof(buf), f))
1312 fputs(buf, stderr);
1313 fclose(f);
1314 }
Darren Tucker09aa4c02010-01-12 19:51:48 +11001315 exit(254);
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001316}
1317
Damien Millerd8cb1f12008-02-10 22:40:12 +11001318/*
1319 * Chroot into a directory after checking it for safety: all path components
1320 * must be root-owned directories with strict permissions.
1321 */
1322static void
1323safely_chroot(const char *path, uid_t uid)
1324{
1325 const char *cp;
deraadt@openbsd.org2ae4f332015-01-16 06:40:12 +00001326 char component[PATH_MAX];
Damien Millerd8cb1f12008-02-10 22:40:12 +11001327 struct stat st;
1328
1329 if (*path != '/')
1330 fatal("chroot path does not begin at root");
1331 if (strlen(path) >= sizeof(component))
1332 fatal("chroot path too long");
1333
1334 /*
1335 * Descend the path, checking that each component is a
1336 * root-owned directory with strict permissions.
1337 */
1338 for (cp = path; cp != NULL;) {
1339 if ((cp = strchr(cp, '/')) == NULL)
1340 strlcpy(component, path, sizeof(component));
1341 else {
1342 cp++;
1343 memcpy(component, path, cp - path);
1344 component[cp - path] = '\0';
1345 }
1346
1347 debug3("%s: checking '%s'", __func__, component);
1348
1349 if (stat(component, &st) != 0)
1350 fatal("%s: stat(\"%s\"): %s", __func__,
1351 component, strerror(errno));
1352 if (st.st_uid != 0 || (st.st_mode & 022) != 0)
1353 fatal("bad ownership or modes for chroot "
1354 "directory %s\"%s\"",
1355 cp == NULL ? "" : "component ", component);
1356 if (!S_ISDIR(st.st_mode))
1357 fatal("chroot path %s\"%s\" is not a directory",
1358 cp == NULL ? "" : "component ", component);
1359
1360 }
1361
1362 if (chdir(path) == -1)
1363 fatal("Unable to chdir to chroot path \"%s\": "
1364 "%s", path, strerror(errno));
1365 if (chroot(path) == -1)
1366 fatal("chroot(\"%s\"): %s", path, strerror(errno));
1367 if (chdir("/") == -1)
1368 fatal("%s: chdir(/) after chroot: %s",
1369 __func__, strerror(errno));
1370 verbose("Changed root directory to \"%s\"", path);
1371}
1372
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001373/* Set login name, uid, gid, and groups. */
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00001374void
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001375do_setusercontext(struct passwd *pw)
1376{
djm@openbsd.org9c935dd2018-06-01 03:33:53 +00001377 char uidstr[32], *chroot_path, *tmp;
Damien Miller54e37732008-02-10 22:48:55 +11001378
Darren Tucker97528352010-11-05 12:03:05 +11001379 platform_setusercontext(pw);
1380
Darren Tuckerb12fe272010-11-05 14:47:01 +11001381 if (platform_privileged_uidswap()) {
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001382#ifdef HAVE_LOGIN_CAP
1383 if (setusercontext(lc, pw, pw->pw_uid,
Damien Millerd8cb1f12008-02-10 22:40:12 +11001384 (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETUSER))) < 0) {
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001385 perror("unable to set user context");
1386 exit(1);
1387 }
1388#else
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001389 if (setlogin(pw->pw_name) < 0)
1390 error("setlogin failed: %s", strerror(errno));
1391 if (setgid(pw->pw_gid) < 0) {
1392 perror("setgid");
1393 exit(1);
1394 }
1395 /* Initialize the group list. */
1396 if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
1397 perror("initgroups");
1398 exit(1);
1399 }
1400 endgrent();
Damien Millerd8cb1f12008-02-10 22:40:12 +11001401#endif
1402
Darren Tucker920612e2010-11-05 12:36:15 +11001403 platform_setusercontext_post_groups(pw);
Damien Miller8b906422010-03-26 11:04:09 +11001404
djm@openbsd.org44fc7cd2015-10-24 22:52:22 +00001405 if (!in_chroot && options.chroot_directory != NULL &&
Damien Millerd8cb1f12008-02-10 22:40:12 +11001406 strcasecmp(options.chroot_directory, "none") != 0) {
Damien Miller54e37732008-02-10 22:48:55 +11001407 tmp = tilde_expand_filename(options.chroot_directory,
1408 pw->pw_uid);
djm@openbsd.org9c935dd2018-06-01 03:33:53 +00001409 snprintf(uidstr, sizeof(uidstr), "%llu",
1410 (unsigned long long)pw->pw_uid);
Damien Miller54e37732008-02-10 22:48:55 +11001411 chroot_path = percent_expand(tmp, "h", pw->pw_dir,
djm@openbsd.org9c935dd2018-06-01 03:33:53 +00001412 "u", pw->pw_name, "U", uidstr, (char *)NULL);
Damien Millerd8cb1f12008-02-10 22:40:12 +11001413 safely_chroot(chroot_path, pw->pw_uid);
Damien Miller54e37732008-02-10 22:48:55 +11001414 free(tmp);
Damien Millerd8cb1f12008-02-10 22:40:12 +11001415 free(chroot_path);
Damien Millera56086b2013-04-23 15:24:18 +10001416 /* Make sure we don't attempt to chroot again */
1417 free(options.chroot_directory);
1418 options.chroot_directory = NULL;
djm@openbsd.org44fc7cd2015-10-24 22:52:22 +00001419 in_chroot = 1;
Damien Millerd8cb1f12008-02-10 22:40:12 +11001420 }
1421
1422#ifdef HAVE_LOGIN_CAP
1423 if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUSER) < 0) {
1424 perror("unable to set user context (setuser)");
1425 exit(1);
1426 }
Damien Miller58528402013-03-15 11:22:37 +11001427 /*
1428 * FreeBSD's setusercontext() will not apply the user's
1429 * own umask setting unless running with the user's UID.
1430 */
1431 (void) setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUMASK);
Damien Millerd8cb1f12008-02-10 22:40:12 +11001432#else
Tim Rice9464ba62014-01-20 17:59:28 -08001433# ifdef USE_LIBIAF
djm@openbsd.org44fc7cd2015-10-24 22:52:22 +00001434 /*
1435 * In a chroot environment, the set_id() will always fail;
1436 * typically because of the lack of necessary authentication
1437 * services and runtime such as ./usr/lib/libiaf.so,
1438 * ./usr/lib/libpam.so.1, and ./etc/passwd We skip it in the
1439 * internal sftp chroot case. We'll lose auditing and ACLs but
1440 * permanently_set_uid will take care of the rest.
1441 */
1442 if (!in_chroot && set_id(pw->pw_name) != 0)
1443 fatal("set_id(%s) Failed", pw->pw_name);
Tim Rice9464ba62014-01-20 17:59:28 -08001444# endif /* USE_LIBIAF */
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001445 /* Permanently switch to the desired uid. */
1446 permanently_set_uid(pw);
1447#endif
Damien Millera56086b2013-04-23 15:24:18 +10001448 } else if (options.chroot_directory != NULL &&
1449 strcasecmp(options.chroot_directory, "none") != 0) {
1450 fatal("server lacks privileges to chroot to ChrootDirectory");
Damien Millerf1a02ae2013-04-23 15:22:13 +10001451 }
Damien Miller1a3ccb02003-02-24 13:04:01 +11001452
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001453 if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
1454 fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
1455}
1456
Ben Lindstrom08105192002-03-22 02:50:06 +00001457static void
Darren Tucker23bc8d02004-02-06 16:24:31 +11001458do_pwchange(Session *s)
1459{
Darren Tucker09991742004-07-17 17:05:14 +10001460 fflush(NULL);
Darren Tucker23bc8d02004-02-06 16:24:31 +11001461 fprintf(stderr, "WARNING: Your password has expired.\n");
1462 if (s->ttyfd != -1) {
Darren Tuckerfc959702004-07-17 16:12:08 +10001463 fprintf(stderr,
Darren Tucker23bc8d02004-02-06 16:24:31 +11001464 "You must change your password now and login again!\n");
Damien Miller14684a12011-05-20 11:23:07 +10001465#ifdef WITH_SELINUX
1466 setexeccon(NULL);
1467#endif
Darren Tucker33370e02005-02-09 22:17:28 +11001468#ifdef PASSWD_NEEDS_USERNAME
1469 execl(_PATH_PASSWD_PROG, "passwd", s->pw->pw_name,
1470 (char *)NULL);
1471#else
Darren Tucker23bc8d02004-02-06 16:24:31 +11001472 execl(_PATH_PASSWD_PROG, "passwd", (char *)NULL);
Darren Tucker33370e02005-02-09 22:17:28 +11001473#endif
Darren Tucker23bc8d02004-02-06 16:24:31 +11001474 perror("passwd");
1475 } else {
1476 fprintf(stderr,
1477 "Password change required but no TTY available.\n");
1478 }
1479 exit(1);
1480}
1481
1482static void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001483child_close_fds(struct ssh *ssh)
Darren Tucker23bc8d02004-02-06 16:24:31 +11001484{
djm@openbsd.org141efe42015-01-14 20:05:27 +00001485 extern int auth_sock;
Damien Miller85b45e02013-07-20 13:21:52 +10001486
djm@openbsd.org141efe42015-01-14 20:05:27 +00001487 if (auth_sock != -1) {
1488 close(auth_sock);
1489 auth_sock = -1;
Damien Miller85b45e02013-07-20 13:21:52 +10001490 }
1491
Darren Tucker23bc8d02004-02-06 16:24:31 +11001492 if (packet_get_connection_in() == packet_get_connection_out())
1493 close(packet_get_connection_in());
1494 else {
1495 close(packet_get_connection_in());
1496 close(packet_get_connection_out());
1497 }
1498 /*
1499 * Close all descriptors related to channels. They will still remain
1500 * open in the parent.
1501 */
1502 /* XXX better use close-on-exec? -markus */
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001503 channel_close_all(ssh);
Darren Tucker23bc8d02004-02-06 16:24:31 +11001504
1505 /*
1506 * Close any extra file descriptors. Note that there may still be
1507 * descriptors left by system functions. They will be closed later.
1508 */
1509 endpwent();
1510
1511 /*
Damien Miller788f2122005-11-05 15:14:59 +11001512 * Close any extra open file descriptors so that we don't have them
Darren Tucker23bc8d02004-02-06 16:24:31 +11001513 * hanging around in clients. Note that we want to do this after
1514 * initgroups, because at least on Solaris 2.3 it leaves file
1515 * descriptors open.
1516 */
Damien Millerf80c3de2010-12-01 12:02:59 +11001517 closefrom(STDERR_FILENO + 1);
Darren Tucker23bc8d02004-02-06 16:24:31 +11001518}
1519
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001520/*
1521 * Performs common processing for the child, such as setting up the
1522 * environment, closing extra file descriptors, setting the user and group
1523 * ids, and executing the command or shell.
1524 */
Damien Millerdfc24252008-02-10 22:29:40 +11001525#define ARGV_MAX 10
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001526void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001527do_child(struct ssh *ssh, Session *s, const char *command)
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001528{
1529 extern char **environ;
1530 char **env;
Damien Millerdfc24252008-02-10 22:29:40 +11001531 char *argv[ARGV_MAX];
djm@openbsd.org83b58182016-08-19 03:18:06 +00001532 const char *shell, *shell0;
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001533 struct passwd *pw = s->pw;
Damien Miller6051c942008-06-16 07:53:16 +10001534 int r = 0;
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001535
1536 /* remove hostkey from the child's memory */
1537 destroy_sensitive_data();
markus@openbsd.org1e0cdf82017-05-31 08:09:45 +00001538 packet_clear_keys();
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001539
Darren Tucker23bc8d02004-02-06 16:24:31 +11001540 /* Force a password change */
1541 if (s->authctxt->force_pwchange) {
1542 do_setusercontext(pw);
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001543 child_close_fds(ssh);
Darren Tucker23bc8d02004-02-06 16:24:31 +11001544 do_pwchange(s);
1545 exit(1);
1546 }
1547
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001548 /*
1549 * Login(1) does this as well, and it needs uid 0 for the "-h"
1550 * switch, so we let login(1) to this for us.
1551 */
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001552#ifdef HAVE_OSF_SIA
djm@openbsd.org83b58182016-08-19 03:18:06 +00001553 session_setup_sia(pw, s->ttyfd == -1 ? NULL : s->tty);
1554 if (!check_quietlogin(s, command))
1555 do_motd();
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001556#else /* HAVE_OSF_SIA */
djm@openbsd.org83b58182016-08-19 03:18:06 +00001557 /* When PAM is enabled we rely on it to do the nologin check */
1558 if (!options.use_pam)
1559 do_nologin(pw);
1560 do_setusercontext(pw);
1561 /*
1562 * PAM session modules in do_setusercontext may have
1563 * generated messages, so if this in an interactive
1564 * login then display them too.
1565 */
1566 if (!check_quietlogin(s, command))
1567 display_loginmsg();
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001568#endif /* HAVE_OSF_SIA */
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001569
Darren Tucker69687f42004-09-11 22:17:26 +10001570#ifdef USE_PAM
djm@openbsd.org83b58182016-08-19 03:18:06 +00001571 if (options.use_pam && !is_pam_session_open()) {
Darren Tucker48554152005-04-21 19:50:55 +10001572 debug3("PAM session not opened, exiting");
Darren Tucker69687f42004-09-11 22:17:26 +10001573 display_loginmsg();
1574 exit(254);
1575 }
1576#endif
1577
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001578 /*
1579 * Get the shell from the password data. An empty shell field is
1580 * legal, and means /bin/sh.
1581 */
1582 shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
Ben Lindstrom46767602002-12-23 02:26:08 +00001583
1584 /*
1585 * Make sure $SHELL points to the shell from the password file,
1586 * even if shell is overridden from login.conf
1587 */
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001588 env = do_setup_env(ssh, s, shell);
Ben Lindstrom46767602002-12-23 02:26:08 +00001589
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001590#ifdef HAVE_LOGIN_CAP
1591 shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);
1592#endif
1593
Damien Millerb38eff82000-04-01 11:09:21 +10001594 /*
1595 * Close the connection descriptors; note that this is the child, and
1596 * the server will still have the socket open, and it is important
1597 * that we do not shutdown it. Note that the descriptors cannot be
1598 * closed before building the environment, as we call
djm@openbsd.org95767262016-03-07 19:02:43 +00001599 * ssh_remote_ipaddr there.
Damien Millerb38eff82000-04-01 11:09:21 +10001600 */
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001601 child_close_fds(ssh);
Damien Millerb38eff82000-04-01 11:09:21 +10001602
Damien Millerb38eff82000-04-01 11:09:21 +10001603 /*
Damien Miller05eda432002-02-10 18:32:28 +11001604 * Must take new environment into use so that .ssh/rc,
1605 * /etc/ssh/sshrc and xauth are run in the proper environment.
Damien Millerb38eff82000-04-01 11:09:21 +10001606 */
1607 environ = env;
1608
Darren Tucker3c78c5e2004-01-23 22:03:10 +11001609#if defined(KRB5) && defined(USE_AFS)
Darren Tucker22ef5082003-12-31 11:37:34 +11001610 /*
1611 * At this point, we check to see if AFS is active and if we have
1612 * a valid Kerberos 5 TGT. If so, it seems like a good idea to see
1613 * if we can (and need to) extend the ticket into an AFS token. If
1614 * we don't do this, we run into potential problems if the user's
1615 * home directory is in AFS and it's not world-readable.
1616 */
1617
1618 if (options.kerberos_get_afs_token && k_hasafs() &&
Damien Miller0dc1bef2005-07-17 17:22:45 +10001619 (s->authctxt->krb5_ctx != NULL)) {
Darren Tucker22ef5082003-12-31 11:37:34 +11001620 char cell[64];
1621
1622 debug("Getting AFS token");
1623
1624 k_setpag();
1625
1626 if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
1627 krb5_afslog(s->authctxt->krb5_ctx,
1628 s->authctxt->krb5_fwd_ccache, cell, NULL);
1629
1630 krb5_afslog_home(s->authctxt->krb5_ctx,
1631 s->authctxt->krb5_fwd_ccache, NULL, NULL, pw->pw_dir);
1632 }
1633#endif
1634
Damien Miller788f2122005-11-05 15:14:59 +11001635 /* Change current directory to the user's home directory. */
Damien Miller139d4cd2001-10-10 15:07:44 +10001636 if (chdir(pw->pw_dir) < 0) {
Damien Miller6051c942008-06-16 07:53:16 +10001637 /* Suppress missing homedir warning for chroot case */
Damien Miller139d4cd2001-10-10 15:07:44 +10001638#ifdef HAVE_LOGIN_CAP
Damien Miller6051c942008-06-16 07:53:16 +10001639 r = login_getcapbool(lc, "requirehome", 0);
Damien Miller139d4cd2001-10-10 15:07:44 +10001640#endif
djm@openbsd.org44fc7cd2015-10-24 22:52:22 +00001641 if (r || !in_chroot) {
Damien Miller6051c942008-06-16 07:53:16 +10001642 fprintf(stderr, "Could not chdir to home "
1643 "directory %s: %s\n", pw->pw_dir,
1644 strerror(errno));
djm@openbsd.org44fc7cd2015-10-24 22:52:22 +00001645 }
Damien Miller6051c942008-06-16 07:53:16 +10001646 if (r)
1647 exit(1);
Damien Miller139d4cd2001-10-10 15:07:44 +10001648 }
1649
Damien Millera1939002008-03-15 17:27:58 +11001650 closefrom(STDERR_FILENO + 1);
1651
djm@openbsd.org7c856852018-03-03 03:15:51 +00001652 do_rc_files(ssh, s, shell);
Ben Lindstromde71cda2001-03-24 00:43:26 +00001653
1654 /* restore SIGPIPE for child */
Damien Miller9ab00b42006-08-05 12:40:11 +10001655 signal(SIGPIPE, SIG_DFL);
Ben Lindstromde71cda2001-03-24 00:43:26 +00001656
Darren Tuckerd6b06a92010-01-08 17:09:11 +11001657 if (s->is_subsystem == SUBSYSTEM_INT_SFTP_ERROR) {
1658 printf("This service allows sftp connections only.\n");
1659 fflush(NULL);
1660 exit(1);
1661 } else if (s->is_subsystem == SUBSYSTEM_INT_SFTP) {
Damien Millerdfc24252008-02-10 22:29:40 +11001662 extern int optind, optreset;
1663 int i;
1664 char *p, *args;
1665
Darren Tuckerac46a912009-06-21 17:55:23 +10001666 setproctitle("%s@%s", s->pw->pw_name, INTERNAL_SFTP_NAME);
Damien Millerd58f5602008-11-03 19:20:49 +11001667 args = xstrdup(command ? command : "sftp-server");
Damien Millerdfc24252008-02-10 22:29:40 +11001668 for (i = 0, (p = strtok(args, " ")); p; (p = strtok(NULL, " ")))
1669 if (i < ARGV_MAX - 1)
1670 argv[i++] = p;
1671 argv[i] = NULL;
1672 optind = optreset = 1;
1673 __progname = argv[0];
Darren Tucker4d6656b2009-10-24 15:04:12 +11001674#ifdef WITH_SELINUX
1675 ssh_selinux_change_context("sftpd_t");
1676#endif
Damien Millerd8cb1f12008-02-10 22:40:12 +11001677 exit(sftp_server_main(i, argv, s->pw));
Damien Millerdfc24252008-02-10 22:29:40 +11001678 }
1679
Darren Tucker695ed392009-10-07 09:02:18 +11001680 fflush(NULL);
1681
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001682 /* Get the last component of the shell name. */
1683 if ((shell0 = strrchr(shell, '/')) != NULL)
1684 shell0++;
1685 else
1686 shell0 = shell;
1687
Damien Millerb38eff82000-04-01 11:09:21 +10001688 /*
1689 * If we have no command, execute the shell. In this case, the shell
1690 * name to be passed in argv[0] is preceded by '-' to indicate that
1691 * this is a login shell.
1692 */
1693 if (!command) {
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001694 char argv0[256];
Damien Millerb38eff82000-04-01 11:09:21 +10001695
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001696 /* Start the shell. Set initial character to '-'. */
1697 argv0[0] = '-';
Damien Millerb38eff82000-04-01 11:09:21 +10001698
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001699 if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1)
1700 >= sizeof(argv0) - 1) {
1701 errno = EINVAL;
Damien Millerb38eff82000-04-01 11:09:21 +10001702 perror(shell);
1703 exit(1);
Damien Millerb38eff82000-04-01 11:09:21 +10001704 }
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001705
1706 /* Execute the shell. */
1707 argv[0] = argv0;
1708 argv[1] = NULL;
1709 execve(shell, argv, env);
1710
1711 /* Executing the shell failed. */
1712 perror(shell);
1713 exit(1);
Damien Millerb38eff82000-04-01 11:09:21 +10001714 }
1715 /*
1716 * Execute the command using the user's shell. This uses the -c
1717 * option to execute the command.
1718 */
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001719 argv[0] = (char *) shell0;
Damien Millerb38eff82000-04-01 11:09:21 +10001720 argv[1] = "-c";
1721 argv[2] = (char *) command;
1722 argv[3] = NULL;
1723 execve(shell, argv, env);
1724 perror(shell);
1725 exit(1);
1726}
1727
Damien Miller7207f642008-05-19 15:34:50 +10001728void
1729session_unused(int id)
1730{
1731 debug3("%s: session id %d unused", __func__, id);
1732 if (id >= options.max_sessions ||
1733 id >= sessions_nalloc) {
1734 fatal("%s: insane session id %d (max %d nalloc %d)",
1735 __func__, id, options.max_sessions, sessions_nalloc);
1736 }
Damien Miller1d2c4562014-02-04 11:18:20 +11001737 memset(&sessions[id], 0, sizeof(*sessions));
Damien Miller7207f642008-05-19 15:34:50 +10001738 sessions[id].self = id;
1739 sessions[id].used = 0;
1740 sessions[id].chanid = -1;
1741 sessions[id].ptyfd = -1;
1742 sessions[id].ttyfd = -1;
1743 sessions[id].ptymaster = -1;
1744 sessions[id].x11_chanids = NULL;
1745 sessions[id].next_unused = sessions_first_unused;
1746 sessions_first_unused = id;
1747}
1748
Damien Millerb38eff82000-04-01 11:09:21 +10001749Session *
1750session_new(void)
1751{
Damien Miller7207f642008-05-19 15:34:50 +10001752 Session *s, *tmp;
1753
1754 if (sessions_first_unused == -1) {
1755 if (sessions_nalloc >= options.max_sessions)
1756 return NULL;
1757 debug2("%s: allocate (allocated %d max %d)",
1758 __func__, sessions_nalloc, options.max_sessions);
deraadt@openbsd.org9e509d42017-05-31 09:15:42 +00001759 tmp = xrecallocarray(sessions, sessions_nalloc,
1760 sessions_nalloc + 1, sizeof(*sessions));
Damien Miller7207f642008-05-19 15:34:50 +10001761 if (tmp == NULL) {
1762 error("%s: cannot allocate %d sessions",
1763 __func__, sessions_nalloc + 1);
1764 return NULL;
Damien Millerb38eff82000-04-01 11:09:21 +10001765 }
Damien Miller7207f642008-05-19 15:34:50 +10001766 sessions = tmp;
1767 session_unused(sessions_nalloc++);
Damien Millerb38eff82000-04-01 11:09:21 +10001768 }
Damien Miller7207f642008-05-19 15:34:50 +10001769
1770 if (sessions_first_unused >= sessions_nalloc ||
1771 sessions_first_unused < 0) {
1772 fatal("%s: insane first_unused %d max %d nalloc %d",
1773 __func__, sessions_first_unused, options.max_sessions,
1774 sessions_nalloc);
Damien Millerb38eff82000-04-01 11:09:21 +10001775 }
Damien Miller7207f642008-05-19 15:34:50 +10001776
1777 s = &sessions[sessions_first_unused];
1778 if (s->used) {
1779 fatal("%s: session %d already used",
1780 __func__, sessions_first_unused);
1781 }
1782 sessions_first_unused = s->next_unused;
1783 s->used = 1;
1784 s->next_unused = -1;
1785 debug("session_new: session %d", s->self);
1786
1787 return s;
Damien Millerb38eff82000-04-01 11:09:21 +10001788}
1789
Ben Lindstrombba81212001-06-25 05:01:22 +00001790static void
Damien Millerb38eff82000-04-01 11:09:21 +10001791session_dump(void)
1792{
1793 int i;
Damien Miller7207f642008-05-19 15:34:50 +10001794 for (i = 0; i < sessions_nalloc; i++) {
Damien Millerb38eff82000-04-01 11:09:21 +10001795 Session *s = &sessions[i];
Damien Miller7207f642008-05-19 15:34:50 +10001796
1797 debug("dump: used %d next_unused %d session %d %p "
1798 "channel %d pid %ld",
Damien Millerb38eff82000-04-01 11:09:21 +10001799 s->used,
Damien Miller7207f642008-05-19 15:34:50 +10001800 s->next_unused,
Damien Millerb38eff82000-04-01 11:09:21 +10001801 s->self,
1802 s,
1803 s->chanid,
Ben Lindstromce0f6342002-06-11 16:42:49 +00001804 (long)s->pid);
Damien Millerb38eff82000-04-01 11:09:21 +10001805 }
1806}
1807
Damien Millerefb4afe2000-04-12 18:45:05 +10001808int
Ben Lindstrombddd5512001-07-04 04:53:53 +00001809session_open(Authctxt *authctxt, int chanid)
Damien Millerefb4afe2000-04-12 18:45:05 +10001810{
1811 Session *s = session_new();
1812 debug("session_open: channel %d", chanid);
1813 if (s == NULL) {
1814 error("no more sessions");
1815 return 0;
1816 }
Ben Lindstrombddd5512001-07-04 04:53:53 +00001817 s->authctxt = authctxt;
1818 s->pw = authctxt->pw;
Damien Miller3e3b5142003-11-17 21:13:40 +11001819 if (s->pw == NULL || !authctxt->valid)
Kevin Steves43cdef32001-02-11 14:12:08 +00001820 fatal("no user for session %d", s->self);
Damien Millerbd483e72000-04-30 10:00:53 +10001821 debug("session_open: session %d: link with channel %d", s->self, chanid);
1822 s->chanid = chanid;
Damien Millerefb4afe2000-04-12 18:45:05 +10001823 return 1;
1824}
1825
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00001826Session *
1827session_by_tty(char *tty)
1828{
1829 int i;
Damien Miller7207f642008-05-19 15:34:50 +10001830 for (i = 0; i < sessions_nalloc; i++) {
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00001831 Session *s = &sessions[i];
1832 if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) {
1833 debug("session_by_tty: session %d tty %s", i, tty);
1834 return s;
1835 }
1836 }
1837 debug("session_by_tty: unknown tty %.100s", tty);
1838 session_dump();
1839 return NULL;
1840}
1841
Ben Lindstrombba81212001-06-25 05:01:22 +00001842static Session *
Damien Millerefb4afe2000-04-12 18:45:05 +10001843session_by_channel(int id)
1844{
1845 int i;
Damien Miller7207f642008-05-19 15:34:50 +10001846 for (i = 0; i < sessions_nalloc; i++) {
Damien Millerefb4afe2000-04-12 18:45:05 +10001847 Session *s = &sessions[i];
1848 if (s->used && s->chanid == id) {
Damien Miller7207f642008-05-19 15:34:50 +10001849 debug("session_by_channel: session %d channel %d",
1850 i, id);
Damien Millerefb4afe2000-04-12 18:45:05 +10001851 return s;
1852 }
1853 }
1854 debug("session_by_channel: unknown channel %d", id);
1855 session_dump();
1856 return NULL;
1857}
1858
Ben Lindstrombba81212001-06-25 05:01:22 +00001859static Session *
Damien Miller2b9b0452005-07-17 17:19:24 +10001860session_by_x11_channel(int id)
1861{
1862 int i, j;
1863
Damien Miller7207f642008-05-19 15:34:50 +10001864 for (i = 0; i < sessions_nalloc; i++) {
Damien Miller2b9b0452005-07-17 17:19:24 +10001865 Session *s = &sessions[i];
1866
1867 if (s->x11_chanids == NULL || !s->used)
1868 continue;
1869 for (j = 0; s->x11_chanids[j] != -1; j++) {
1870 if (s->x11_chanids[j] == id) {
1871 debug("session_by_x11_channel: session %d "
1872 "channel %d", s->self, id);
1873 return s;
1874 }
1875 }
1876 }
1877 debug("session_by_x11_channel: unknown channel %d", id);
1878 session_dump();
1879 return NULL;
1880}
1881
1882static Session *
Damien Millerefb4afe2000-04-12 18:45:05 +10001883session_by_pid(pid_t pid)
1884{
1885 int i;
Ben Lindstromce0f6342002-06-11 16:42:49 +00001886 debug("session_by_pid: pid %ld", (long)pid);
Damien Miller7207f642008-05-19 15:34:50 +10001887 for (i = 0; i < sessions_nalloc; i++) {
Damien Millerefb4afe2000-04-12 18:45:05 +10001888 Session *s = &sessions[i];
1889 if (s->used && s->pid == pid)
1890 return s;
1891 }
Ben Lindstromce0f6342002-06-11 16:42:49 +00001892 error("session_by_pid: unknown pid %ld", (long)pid);
Damien Millerefb4afe2000-04-12 18:45:05 +10001893 session_dump();
1894 return NULL;
1895}
1896
Ben Lindstrombba81212001-06-25 05:01:22 +00001897static int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001898session_window_change_req(struct ssh *ssh, Session *s)
Damien Millerefb4afe2000-04-12 18:45:05 +10001899{
1900 s->col = packet_get_int();
1901 s->row = packet_get_int();
1902 s->xpixel = packet_get_int();
1903 s->ypixel = packet_get_int();
Damien Miller48b03fc2002-01-22 23:11:40 +11001904 packet_check_eom();
Damien Millerefb4afe2000-04-12 18:45:05 +10001905 pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
1906 return 1;
1907}
1908
Ben Lindstrombba81212001-06-25 05:01:22 +00001909static int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001910session_pty_req(struct ssh *ssh, Session *s)
Damien Millerefb4afe2000-04-12 18:45:05 +10001911{
Ben Lindstrom46c16222000-12-22 01:43:59 +00001912 u_int len;
Ben Lindstromae8e2d32001-04-14 23:13:02 +00001913 int n_bytes;
Ben Lindstrom6328ab32002-03-22 02:54:23 +00001914
djm@openbsd.org7c856852018-03-03 03:15:51 +00001915 if (!auth_opts->permit_pty_flag || !options.permit_tty) {
1916 debug("Allocating a pty not permitted for this connection.");
Damien Millerf6d9e222000-06-18 14:50:44 +10001917 return 0;
Ben Lindstrom49c12602001-06-13 04:37:36 +00001918 }
1919 if (s->ttyfd != -1) {
1920 packet_disconnect("Protocol error: you already have a pty.");
Damien Miller4af51302000-04-16 11:18:38 +10001921 return 0;
Ben Lindstrom49c12602001-06-13 04:37:36 +00001922 }
1923
Damien Millerefb4afe2000-04-12 18:45:05 +10001924 s->term = packet_get_string(&len);
markus@openbsd.org6cb6dcf2016-08-13 17:47:40 +00001925 s->col = packet_get_int();
1926 s->row = packet_get_int();
Damien Millerefb4afe2000-04-12 18:45:05 +10001927 s->xpixel = packet_get_int();
1928 s->ypixel = packet_get_int();
1929
1930 if (strcmp(s->term, "") == 0) {
Darren Tuckera627d422013-06-02 07:31:17 +10001931 free(s->term);
Damien Millerefb4afe2000-04-12 18:45:05 +10001932 s->term = NULL;
1933 }
Ben Lindstrom49c12602001-06-13 04:37:36 +00001934
Damien Millerefb4afe2000-04-12 18:45:05 +10001935 /* Allocate a pty and open it. */
Ben Lindstrom49c12602001-06-13 04:37:36 +00001936 debug("Allocating pty.");
Damien Miller7207f642008-05-19 15:34:50 +10001937 if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty,
1938 sizeof(s->tty)))) {
Darren Tuckera627d422013-06-02 07:31:17 +10001939 free(s->term);
Damien Millerefb4afe2000-04-12 18:45:05 +10001940 s->term = NULL;
1941 s->ptyfd = -1;
1942 s->ttyfd = -1;
1943 error("session_pty_req: session %d alloc failed", s->self);
Damien Miller4af51302000-04-16 11:18:38 +10001944 return 0;
Damien Millerefb4afe2000-04-12 18:45:05 +10001945 }
1946 debug("session_pty_req: session %d alloc %s", s->self, s->tty);
Ben Lindstrom49c12602001-06-13 04:37:36 +00001947
markus@openbsd.org6cb6dcf2016-08-13 17:47:40 +00001948 n_bytes = packet_remaining();
Ben Lindstrom49c12602001-06-13 04:37:36 +00001949 tty_parse_modes(s->ttyfd, &n_bytes);
1950
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00001951 if (!use_privsep)
1952 pty_setowner(s->pw, s->tty);
Ben Lindstrom49c12602001-06-13 04:37:36 +00001953
1954 /* Set window size from the packet. */
Damien Millerefb4afe2000-04-12 18:45:05 +10001955 pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
1956
Damien Miller48b03fc2002-01-22 23:11:40 +11001957 packet_check_eom();
Damien Millere247cc42000-05-07 12:03:14 +10001958 session_proctitle(s);
Damien Millerefb4afe2000-04-12 18:45:05 +10001959 return 1;
1960}
1961
Ben Lindstrombba81212001-06-25 05:01:22 +00001962static int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001963session_subsystem_req(struct ssh *ssh, Session *s)
Damien Millerbd483e72000-04-30 10:00:53 +10001964{
Damien Millerae452462001-10-10 15:08:06 +10001965 struct stat st;
Ben Lindstrom46c16222000-12-22 01:43:59 +00001966 u_int len;
Damien Millerbd483e72000-04-30 10:00:53 +10001967 int success = 0;
Damien Miller71df7522013-10-15 12:12:02 +11001968 char *prog, *cmd;
Damien Millereccb9de2005-06-17 12:59:34 +10001969 u_int i;
Damien Millerbd483e72000-04-30 10:00:53 +10001970
Damien Miller71df7522013-10-15 12:12:02 +11001971 s->subsys = packet_get_string(&len);
Damien Miller48b03fc2002-01-22 23:11:40 +11001972 packet_check_eom();
Damien Miller71df7522013-10-15 12:12:02 +11001973 debug2("subsystem request for %.100s by user %s", s->subsys,
Damien Miller1b2b61e2010-06-26 09:47:43 +10001974 s->pw->pw_name);
Damien Millerbd483e72000-04-30 10:00:53 +10001975
Damien Millerf6d9e222000-06-18 14:50:44 +10001976 for (i = 0; i < options.num_subsystems; i++) {
Damien Miller71df7522013-10-15 12:12:02 +11001977 if (strcmp(s->subsys, options.subsystem_name[i]) == 0) {
Damien Miller917f9b62006-07-10 20:36:47 +10001978 prog = options.subsystem_command[i];
1979 cmd = options.subsystem_args[i];
Darren Tuckerc3dc4042010-01-08 17:09:50 +11001980 if (strcmp(INTERNAL_SFTP_NAME, prog) == 0) {
Damien Millerdfc24252008-02-10 22:29:40 +11001981 s->is_subsystem = SUBSYSTEM_INT_SFTP;
Darren Tuckerc3dc4042010-01-08 17:09:50 +11001982 debug("subsystem: %s", prog);
Damien Millerdfc24252008-02-10 22:29:40 +11001983 } else {
Darren Tuckerc3dc4042010-01-08 17:09:50 +11001984 if (stat(prog, &st) < 0)
1985 debug("subsystem: cannot stat %s: %s",
1986 prog, strerror(errno));
Damien Millerdfc24252008-02-10 22:29:40 +11001987 s->is_subsystem = SUBSYSTEM_EXT;
Darren Tuckerc3dc4042010-01-08 17:09:50 +11001988 debug("subsystem: exec() %s", cmd);
Damien Millerae452462001-10-10 15:08:06 +10001989 }
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00001990 success = do_exec(ssh, s, cmd) == 0;
Damien Miller5fab4b92002-02-05 12:15:07 +11001991 break;
Damien Millerf6d9e222000-06-18 14:50:44 +10001992 }
1993 }
1994
1995 if (!success)
Damien Miller71df7522013-10-15 12:12:02 +11001996 logit("subsystem request for %.100s by user %s failed, "
1997 "subsystem not found", s->subsys, s->pw->pw_name);
Damien Millerf6d9e222000-06-18 14:50:44 +10001998
Damien Millerbd483e72000-04-30 10:00:53 +10001999 return success;
2000}
2001
Ben Lindstrombba81212001-06-25 05:01:22 +00002002static int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002003session_x11_req(struct ssh *ssh, Session *s)
Damien Millerbd483e72000-04-30 10:00:53 +10002004{
Ben Lindstrom768176b2001-06-09 01:29:12 +00002005 int success;
Damien Millerbd483e72000-04-30 10:00:53 +10002006
Damien Miller2b9b0452005-07-17 17:19:24 +10002007 if (s->auth_proto != NULL || s->auth_data != NULL) {
2008 error("session_x11_req: session %d: "
Darren Tucker63551872005-12-20 16:14:15 +11002009 "x11 forwarding already active", s->self);
Damien Miller2b9b0452005-07-17 17:19:24 +10002010 return 0;
2011 }
Damien Millerbd483e72000-04-30 10:00:53 +10002012 s->single_connection = packet_get_char();
2013 s->auth_proto = packet_get_string(NULL);
2014 s->auth_data = packet_get_string(NULL);
2015 s->screen = packet_get_int();
Damien Miller48b03fc2002-01-22 23:11:40 +11002016 packet_check_eom();
Damien Millerbd483e72000-04-30 10:00:53 +10002017
djm@openbsd.org4b4bfb02016-03-10 11:47:57 +00002018 if (xauth_valid_string(s->auth_proto) &&
2019 xauth_valid_string(s->auth_data))
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002020 success = session_setup_x11fwd(ssh, s);
djm@openbsd.org4b4bfb02016-03-10 11:47:57 +00002021 else {
2022 success = 0;
2023 error("Invalid X11 forwarding data");
2024 }
Ben Lindstrom768176b2001-06-09 01:29:12 +00002025 if (!success) {
Darren Tuckera627d422013-06-02 07:31:17 +10002026 free(s->auth_proto);
2027 free(s->auth_data);
Ben Lindstrom88259fb2001-06-12 00:21:34 +00002028 s->auth_proto = NULL;
2029 s->auth_data = NULL;
Damien Millerbd483e72000-04-30 10:00:53 +10002030 }
Ben Lindstrom768176b2001-06-09 01:29:12 +00002031 return success;
Damien Millerbd483e72000-04-30 10:00:53 +10002032}
2033
Ben Lindstrombba81212001-06-25 05:01:22 +00002034static int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002035session_shell_req(struct ssh *ssh, Session *s)
Damien Millerf6d9e222000-06-18 14:50:44 +10002036{
Damien Miller48b03fc2002-01-22 23:11:40 +11002037 packet_check_eom();
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002038 return do_exec(ssh, s, NULL) == 0;
Damien Millerf6d9e222000-06-18 14:50:44 +10002039}
2040
Ben Lindstrombba81212001-06-25 05:01:22 +00002041static int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002042session_exec_req(struct ssh *ssh, Session *s)
Damien Millerf6d9e222000-06-18 14:50:44 +10002043{
Damien Miller7207f642008-05-19 15:34:50 +10002044 u_int len, success;
2045
Damien Millerf6d9e222000-06-18 14:50:44 +10002046 char *command = packet_get_string(&len);
Damien Miller48b03fc2002-01-22 23:11:40 +11002047 packet_check_eom();
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002048 success = do_exec(ssh, s, command) == 0;
Darren Tuckera627d422013-06-02 07:31:17 +10002049 free(command);
Damien Miller7207f642008-05-19 15:34:50 +10002050 return success;
Damien Millerf6d9e222000-06-18 14:50:44 +10002051}
2052
Ben Lindstrombba81212001-06-25 05:01:22 +00002053static int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002054session_break_req(struct ssh *ssh, Session *s)
Damien Miller54c45982003-05-15 10:20:13 +10002055{
Damien Miller54c45982003-05-15 10:20:13 +10002056
Darren Tucker1f8311c2004-05-13 16:39:33 +10002057 packet_get_int(); /* ignored */
Damien Miller54c45982003-05-15 10:20:13 +10002058 packet_check_eom();
2059
Darren Tucker9c5d5532011-11-04 10:55:24 +11002060 if (s->ptymaster == -1 || tcsendbreak(s->ptymaster, 0) < 0)
Damien Miller54c45982003-05-15 10:20:13 +10002061 return 0;
Damien Miller54c45982003-05-15 10:20:13 +10002062 return 1;
2063}
2064
2065static int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002066session_env_req(struct ssh *ssh, Session *s)
Darren Tucker46bc0752004-05-02 22:11:30 +10002067{
2068 char *name, *val;
2069 u_int name_len, val_len, i;
2070
Damien Miller8569eba2014-03-04 09:35:17 +11002071 name = packet_get_cstring(&name_len);
2072 val = packet_get_cstring(&val_len);
Darren Tucker46bc0752004-05-02 22:11:30 +10002073 packet_check_eom();
2074
2075 /* Don't set too many environment variables */
2076 if (s->num_env > 128) {
2077 debug2("Ignoring env request %s: too many env vars", name);
2078 goto fail;
2079 }
2080
2081 for (i = 0; i < options.num_accept_env; i++) {
2082 if (match_pattern(name, options.accept_env[i])) {
2083 debug2("Setting env %d: %s=%s", s->num_env, name, val);
deraadt@openbsd.org9e509d42017-05-31 09:15:42 +00002084 s->env = xrecallocarray(s->env, s->num_env,
2085 s->num_env + 1, sizeof(*s->env));
Darren Tucker46bc0752004-05-02 22:11:30 +10002086 s->env[s->num_env].name = name;
2087 s->env[s->num_env].val = val;
2088 s->num_env++;
2089 return (1);
2090 }
2091 }
2092 debug2("Ignoring env request %s: disallowed name", name);
2093
2094 fail:
Darren Tuckera627d422013-06-02 07:31:17 +10002095 free(name);
2096 free(val);
Darren Tucker46bc0752004-05-02 22:11:30 +10002097 return (0);
2098}
2099
2100static int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002101session_auth_agent_req(struct ssh *ssh, Session *s)
Damien Miller0bc1bd82000-11-13 22:57:25 +11002102{
2103 static int called = 0;
djm@openbsd.org7c856852018-03-03 03:15:51 +00002104
Damien Miller48b03fc2002-01-22 23:11:40 +11002105 packet_check_eom();
djm@openbsd.org7c856852018-03-03 03:15:51 +00002106 if (!auth_opts->permit_agent_forwarding_flag ||
2107 !options.allow_agent_forwarding) {
2108 debug("%s: agent forwarding disabled", __func__);
Ben Lindstrom14920292000-11-21 21:24:55 +00002109 return 0;
2110 }
Damien Miller0bc1bd82000-11-13 22:57:25 +11002111 if (called) {
2112 return 0;
2113 } else {
2114 called = 1;
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002115 return auth_input_request_forwarding(ssh, s->pw);
Damien Miller0bc1bd82000-11-13 22:57:25 +11002116 }
2117}
2118
Damien Millerc7ef63d2002-02-05 12:21:42 +11002119int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002120session_input_channel_req(struct ssh *ssh, Channel *c, const char *rtype)
Damien Millerefb4afe2000-04-12 18:45:05 +10002121{
Damien Millerefb4afe2000-04-12 18:45:05 +10002122 int success = 0;
Damien Millerefb4afe2000-04-12 18:45:05 +10002123 Session *s;
Damien Millerefb4afe2000-04-12 18:45:05 +10002124
Damien Millerc7ef63d2002-02-05 12:21:42 +11002125 if ((s = session_by_channel(c->self)) == NULL) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002126 logit("%s: no session %d req %.100s", __func__, c->self, rtype);
Damien Millerc7ef63d2002-02-05 12:21:42 +11002127 return 0;
2128 }
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002129 debug("%s: session %d req %s", __func__, s->self, rtype);
Damien Millerefb4afe2000-04-12 18:45:05 +10002130
2131 /*
Ben Lindstromfc9b07d2001-03-22 01:27:23 +00002132 * a session is in LARVAL state until a shell, a command
2133 * or a subsystem is executed
Damien Millerefb4afe2000-04-12 18:45:05 +10002134 */
2135 if (c->type == SSH_CHANNEL_LARVAL) {
2136 if (strcmp(rtype, "shell") == 0) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002137 success = session_shell_req(ssh, s);
Damien Millerefb4afe2000-04-12 18:45:05 +10002138 } else if (strcmp(rtype, "exec") == 0) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002139 success = session_exec_req(ssh, s);
Damien Millerefb4afe2000-04-12 18:45:05 +10002140 } else if (strcmp(rtype, "pty-req") == 0) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002141 success = session_pty_req(ssh, s);
Damien Millerbd483e72000-04-30 10:00:53 +10002142 } else if (strcmp(rtype, "x11-req") == 0) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002143 success = session_x11_req(ssh, s);
Damien Miller0bc1bd82000-11-13 22:57:25 +11002144 } else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002145 success = session_auth_agent_req(ssh, s);
Damien Millerbd483e72000-04-30 10:00:53 +10002146 } else if (strcmp(rtype, "subsystem") == 0) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002147 success = session_subsystem_req(ssh, s);
Darren Tucker46bc0752004-05-02 22:11:30 +10002148 } else if (strcmp(rtype, "env") == 0) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002149 success = session_env_req(ssh, s);
Damien Millerefb4afe2000-04-12 18:45:05 +10002150 }
2151 }
2152 if (strcmp(rtype, "window-change") == 0) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002153 success = session_window_change_req(ssh, s);
Damien Millera6b1d162004-06-30 22:41:07 +10002154 } else if (strcmp(rtype, "break") == 0) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002155 success = session_break_req(ssh, s);
Damien Millerefb4afe2000-04-12 18:45:05 +10002156 }
Damien Millera6b1d162004-06-30 22:41:07 +10002157
Damien Millerc7ef63d2002-02-05 12:21:42 +11002158 return success;
Damien Millerefb4afe2000-04-12 18:45:05 +10002159}
2160
2161void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002162session_set_fds(struct ssh *ssh, Session *s,
2163 int fdin, int fdout, int fderr, int ignore_fderr, int is_tty)
Damien Millerefb4afe2000-04-12 18:45:05 +10002164{
Damien Millerefb4afe2000-04-12 18:45:05 +10002165 /*
2166 * now that have a child and a pipe to the child,
2167 * we can activate our channel and register the fd's
2168 */
2169 if (s->chanid == -1)
2170 fatal("no channel for session %d", s->self);
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002171 channel_set_fds(ssh, s->chanid,
Damien Millerefb4afe2000-04-12 18:45:05 +10002172 fdout, fdin, fderr,
Damien Miller8853ca52010-06-26 10:00:14 +10002173 ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
Darren Tuckered3cdc02008-06-16 23:29:18 +10002174 1, is_tty, CHAN_SES_WINDOW_DEFAULT);
Damien Millerefb4afe2000-04-12 18:45:05 +10002175}
2176
Ben Lindstrom7eaf8e42001-06-13 04:35:43 +00002177/*
2178 * Function to perform pty cleanup. Also called if we get aborted abnormally
2179 * (e.g., due to a dropped connection).
2180 */
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00002181void
Darren Tucker3e33cec2003-10-02 16:12:36 +10002182session_pty_cleanup2(Session *s)
Damien Millerb38eff82000-04-01 11:09:21 +10002183{
Ben Lindstrom7eaf8e42001-06-13 04:35:43 +00002184 if (s == NULL) {
2185 error("session_pty_cleanup: no session");
2186 return;
2187 }
2188 if (s->ttyfd == -1)
Damien Millerb38eff82000-04-01 11:09:21 +10002189 return;
2190
Kevin Steves43cdef32001-02-11 14:12:08 +00002191 debug("session_pty_cleanup: session %d release %s", s->self, s->tty);
Damien Millerb38eff82000-04-01 11:09:21 +10002192
Damien Millerb38eff82000-04-01 11:09:21 +10002193 /* Record that the user has logged out. */
Ben Lindstrom7eaf8e42001-06-13 04:35:43 +00002194 if (s->pid != 0)
Tim Ricee06ae4a2002-02-24 17:56:46 -08002195 record_logout(s->pid, s->tty, s->pw->pw_name);
Damien Millerb38eff82000-04-01 11:09:21 +10002196
2197 /* Release the pseudo-tty. */
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00002198 if (getuid() == 0)
2199 pty_release(s->tty);
Damien Millerb38eff82000-04-01 11:09:21 +10002200
2201 /*
2202 * Close the server side of the socket pairs. We must do this after
2203 * the pty cleanup, so that another process doesn't get this pty
2204 * while we're still cleaning up.
2205 */
Damien Miller7207f642008-05-19 15:34:50 +10002206 if (s->ptymaster != -1 && close(s->ptymaster) < 0)
2207 error("close(s->ptymaster/%d): %s",
2208 s->ptymaster, strerror(errno));
Damien Miller0585d512001-10-12 11:35:50 +10002209
2210 /* unlink pty from session */
2211 s->ttyfd = -1;
Damien Millerb38eff82000-04-01 11:09:21 +10002212}
Damien Millerefb4afe2000-04-12 18:45:05 +10002213
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00002214void
Darren Tucker3e33cec2003-10-02 16:12:36 +10002215session_pty_cleanup(Session *s)
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00002216{
Darren Tucker3e33cec2003-10-02 16:12:36 +10002217 PRIVSEP(session_pty_cleanup2(s));
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00002218}
2219
Damien Miller5a80bba2002-09-04 16:39:02 +10002220static char *
2221sig2name(int sig)
2222{
2223#define SSH_SIG(x) if (sig == SIG ## x) return #x
2224 SSH_SIG(ABRT);
2225 SSH_SIG(ALRM);
2226 SSH_SIG(FPE);
2227 SSH_SIG(HUP);
2228 SSH_SIG(ILL);
2229 SSH_SIG(INT);
2230 SSH_SIG(KILL);
2231 SSH_SIG(PIPE);
2232 SSH_SIG(QUIT);
2233 SSH_SIG(SEGV);
2234 SSH_SIG(TERM);
2235 SSH_SIG(USR1);
2236 SSH_SIG(USR2);
2237#undef SSH_SIG
2238 return "SIG@openssh.com";
2239}
2240
Ben Lindstrombba81212001-06-25 05:01:22 +00002241static void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002242session_close_x11(struct ssh *ssh, int id)
Damien Miller2b9b0452005-07-17 17:19:24 +10002243{
2244 Channel *c;
2245
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002246 if ((c = channel_by_id(ssh, id)) == NULL) {
2247 debug("%s: x11 channel %d missing", __func__, id);
Damien Miller2b9b0452005-07-17 17:19:24 +10002248 } else {
2249 /* Detach X11 listener */
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002250 debug("%s: detach x11 channel %d", __func__, id);
2251 channel_cancel_cleanup(ssh, id);
Damien Miller2b9b0452005-07-17 17:19:24 +10002252 if (c->ostate != CHAN_OUTPUT_CLOSED)
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002253 chan_mark_dead(ssh, c);
Damien Miller2b9b0452005-07-17 17:19:24 +10002254 }
2255}
2256
2257static void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002258session_close_single_x11(struct ssh *ssh, int id, void *arg)
Damien Miller2b9b0452005-07-17 17:19:24 +10002259{
2260 Session *s;
2261 u_int i;
2262
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002263 debug3("%s: channel %d", __func__, id);
2264 channel_cancel_cleanup(ssh, id);
Darren Tucker82a3d2b2007-02-19 22:10:25 +11002265 if ((s = session_by_x11_channel(id)) == NULL)
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002266 fatal("%s: no x11 channel %d", __func__, id);
Damien Miller2b9b0452005-07-17 17:19:24 +10002267 for (i = 0; s->x11_chanids[i] != -1; i++) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002268 debug("%s: session %d: closing channel %d",
2269 __func__, s->self, s->x11_chanids[i]);
Damien Miller2b9b0452005-07-17 17:19:24 +10002270 /*
2271 * The channel "id" is already closing, but make sure we
2272 * close all of its siblings.
2273 */
2274 if (s->x11_chanids[i] != id)
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002275 session_close_x11(ssh, s->x11_chanids[i]);
Damien Miller2b9b0452005-07-17 17:19:24 +10002276 }
Darren Tuckera627d422013-06-02 07:31:17 +10002277 free(s->x11_chanids);
Damien Miller2b9b0452005-07-17 17:19:24 +10002278 s->x11_chanids = NULL;
Darren Tuckera627d422013-06-02 07:31:17 +10002279 free(s->display);
2280 s->display = NULL;
2281 free(s->auth_proto);
2282 s->auth_proto = NULL;
2283 free(s->auth_data);
2284 s->auth_data = NULL;
2285 free(s->auth_display);
2286 s->auth_display = NULL;
Damien Miller2b9b0452005-07-17 17:19:24 +10002287}
2288
2289static void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002290session_exit_message(struct ssh *ssh, Session *s, int status)
Damien Millerefb4afe2000-04-12 18:45:05 +10002291{
2292 Channel *c;
Damien Millerf3dcf1f2002-02-08 22:06:48 +11002293
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002294 if ((c = channel_lookup(ssh, s->chanid)) == NULL)
2295 fatal("%s: session %d: no channel %d",
2296 __func__, s->self, s->chanid);
2297 debug("%s: session %d channel %d pid %ld",
2298 __func__, s->self, s->chanid, (long)s->pid);
Damien Millerefb4afe2000-04-12 18:45:05 +10002299
2300 if (WIFEXITED(status)) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002301 channel_request_start(ssh, s->chanid, "exit-status", 0);
Damien Millerefb4afe2000-04-12 18:45:05 +10002302 packet_put_int(WEXITSTATUS(status));
2303 packet_send();
2304 } else if (WIFSIGNALED(status)) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002305 channel_request_start(ssh, s->chanid, "exit-signal", 0);
Damien Miller5a80bba2002-09-04 16:39:02 +10002306 packet_put_cstring(sig2name(WTERMSIG(status)));
Damien Millerf3c6cf12000-05-17 22:08:29 +10002307#ifdef WCOREDUMP
Damien Miller767087b2008-03-07 18:32:42 +11002308 packet_put_char(WCOREDUMP(status)? 1 : 0);
Damien Millerf3c6cf12000-05-17 22:08:29 +10002309#else /* WCOREDUMP */
2310 packet_put_char(0);
2311#endif /* WCOREDUMP */
Damien Millerefb4afe2000-04-12 18:45:05 +10002312 packet_put_cstring("");
2313 packet_put_cstring("");
2314 packet_send();
2315 } else {
2316 /* Some weird exit cause. Just exit. */
2317 packet_disconnect("wait returned status %04x.", status);
2318 }
2319
2320 /* disconnect channel */
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002321 debug("%s: release channel %d", __func__, s->chanid);
Damien Miller39eda6e2005-11-05 14:52:50 +11002322
2323 /*
2324 * Adjust cleanup callback attachment to send close messages when
Damien Millerc91e5562006-03-26 13:58:55 +11002325 * the channel gets EOF. The session will be then be closed
Damien Miller39eda6e2005-11-05 14:52:50 +11002326 * by session_close_by_channel when the childs close their fds.
2327 */
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002328 channel_register_cleanup(ssh, c->self, session_close_by_channel, 1);
Damien Miller39eda6e2005-11-05 14:52:50 +11002329
Damien Miller166fca82000-04-20 07:42:21 +10002330 /*
2331 * emulate a write failure with 'chan_write_failed', nobody will be
2332 * interested in data we write.
2333 * Note that we must not call 'chan_read_failed', since there could
2334 * be some more data waiting in the pipe.
2335 */
Damien Millerbd483e72000-04-30 10:00:53 +10002336 if (c->ostate != CHAN_OUTPUT_CLOSED)
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002337 chan_write_failed(ssh, c);
Damien Millerefb4afe2000-04-12 18:45:05 +10002338}
2339
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00002340void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002341session_close(struct ssh *ssh, Session *s)
Damien Millerefb4afe2000-04-12 18:45:05 +10002342{
Damien Millereccb9de2005-06-17 12:59:34 +10002343 u_int i;
Darren Tucker46bc0752004-05-02 22:11:30 +10002344
djm@openbsd.org5a0fcb72016-02-16 03:37:48 +00002345 verbose("Close session: user %s from %.200s port %d id %d",
2346 s->pw->pw_name,
djm@openbsd.org95767262016-03-07 19:02:43 +00002347 ssh_remote_ipaddr(ssh),
2348 ssh_remote_port(ssh),
djm@openbsd.org5a0fcb72016-02-16 03:37:48 +00002349 s->self);
2350
Darren Tucker3e33cec2003-10-02 16:12:36 +10002351 if (s->ttyfd != -1)
Ben Lindstrom7eaf8e42001-06-13 04:35:43 +00002352 session_pty_cleanup(s);
Darren Tuckera627d422013-06-02 07:31:17 +10002353 free(s->term);
2354 free(s->display);
2355 free(s->x11_chanids);
2356 free(s->auth_display);
2357 free(s->auth_data);
2358 free(s->auth_proto);
Damien Miller71df7522013-10-15 12:12:02 +11002359 free(s->subsys);
Damien Millerd5fe0ba2006-08-30 11:07:39 +10002360 if (s->env != NULL) {
2361 for (i = 0; i < s->num_env; i++) {
Darren Tuckera627d422013-06-02 07:31:17 +10002362 free(s->env[i].name);
2363 free(s->env[i].val);
Damien Millerd5fe0ba2006-08-30 11:07:39 +10002364 }
Darren Tuckera627d422013-06-02 07:31:17 +10002365 free(s->env);
Damien Millerd5fe0ba2006-08-30 11:07:39 +10002366 }
Damien Millere247cc42000-05-07 12:03:14 +10002367 session_proctitle(s);
Damien Miller7207f642008-05-19 15:34:50 +10002368 session_unused(s->self);
Damien Millerefb4afe2000-04-12 18:45:05 +10002369}
2370
2371void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002372session_close_by_pid(struct ssh *ssh, pid_t pid, int status)
Damien Millerefb4afe2000-04-12 18:45:05 +10002373{
2374 Session *s = session_by_pid(pid);
2375 if (s == NULL) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002376 debug("%s: no session for pid %ld", __func__, (long)pid);
Damien Millerefb4afe2000-04-12 18:45:05 +10002377 return;
2378 }
2379 if (s->chanid != -1)
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002380 session_exit_message(ssh, s, status);
Damien Miller39eda6e2005-11-05 14:52:50 +11002381 if (s->ttyfd != -1)
2382 session_pty_cleanup(s);
Tim Rice83d2f5f2006-02-07 15:17:44 -08002383 s->pid = 0;
Damien Millerefb4afe2000-04-12 18:45:05 +10002384}
2385
2386/*
2387 * this is called when a channel dies before
2388 * the session 'child' itself dies
2389 */
2390void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002391session_close_by_channel(struct ssh *ssh, int id, void *arg)
Damien Millerefb4afe2000-04-12 18:45:05 +10002392{
2393 Session *s = session_by_channel(id);
Damien Miller39eda6e2005-11-05 14:52:50 +11002394 u_int i;
Damien Miller2b9b0452005-07-17 17:19:24 +10002395
Damien Millerefb4afe2000-04-12 18:45:05 +10002396 if (s == NULL) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002397 debug("%s: no session for id %d", __func__, id);
Damien Millerefb4afe2000-04-12 18:45:05 +10002398 return;
2399 }
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002400 debug("%s: channel %d child %ld", __func__, id, (long)s->pid);
Damien Miller3ec27592001-10-12 11:35:04 +10002401 if (s->pid != 0) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002402 debug("%s: channel %d: has child", __func__, id);
Damien Miller0585d512001-10-12 11:35:50 +10002403 /*
2404 * delay detach of session, but release pty, since
2405 * the fd's to the child are already closed
2406 */
Darren Tucker3e33cec2003-10-02 16:12:36 +10002407 if (s->ttyfd != -1)
Damien Miller0585d512001-10-12 11:35:50 +10002408 session_pty_cleanup(s);
Damien Miller3ec27592001-10-12 11:35:04 +10002409 return;
2410 }
2411 /* detach by removing callback */
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002412 channel_cancel_cleanup(ssh, s->chanid);
Damien Miller39eda6e2005-11-05 14:52:50 +11002413
2414 /* Close any X11 listeners associated with this session */
2415 if (s->x11_chanids != NULL) {
2416 for (i = 0; s->x11_chanids[i] != -1; i++) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002417 session_close_x11(ssh, s->x11_chanids[i]);
Damien Miller39eda6e2005-11-05 14:52:50 +11002418 s->x11_chanids[i] = -1;
2419 }
2420 }
2421
Damien Millerefb4afe2000-04-12 18:45:05 +10002422 s->chanid = -1;
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002423 session_close(ssh, s);
Damien Miller52b77be2001-10-10 15:14:37 +10002424}
2425
2426void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002427session_destroy_all(struct ssh *ssh, void (*closefunc)(Session *))
Damien Miller52b77be2001-10-10 15:14:37 +10002428{
2429 int i;
Damien Miller7207f642008-05-19 15:34:50 +10002430 for (i = 0; i < sessions_nalloc; i++) {
Damien Miller52b77be2001-10-10 15:14:37 +10002431 Session *s = &sessions[i];
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00002432 if (s->used) {
2433 if (closefunc != NULL)
2434 closefunc(s);
2435 else
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002436 session_close(ssh, s);
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00002437 }
Damien Miller52b77be2001-10-10 15:14:37 +10002438 }
Damien Millerefb4afe2000-04-12 18:45:05 +10002439}
2440
Ben Lindstrombba81212001-06-25 05:01:22 +00002441static char *
Damien Millere247cc42000-05-07 12:03:14 +10002442session_tty_list(void)
2443{
2444 static char buf[1024];
2445 int i;
Damien Millera8ed44b2003-01-10 09:53:12 +11002446 char *cp;
2447
Damien Millere247cc42000-05-07 12:03:14 +10002448 buf[0] = '\0';
Damien Miller7207f642008-05-19 15:34:50 +10002449 for (i = 0; i < sessions_nalloc; i++) {
Damien Millere247cc42000-05-07 12:03:14 +10002450 Session *s = &sessions[i];
2451 if (s->used && s->ttyfd != -1) {
Damien Miller787b2ec2003-11-21 23:56:47 +11002452
Damien Millera8ed44b2003-01-10 09:53:12 +11002453 if (strncmp(s->tty, "/dev/", 5) != 0) {
2454 cp = strrchr(s->tty, '/');
2455 cp = (cp == NULL) ? s->tty : cp + 1;
2456 } else
2457 cp = s->tty + 5;
Damien Miller787b2ec2003-11-21 23:56:47 +11002458
Damien Millere247cc42000-05-07 12:03:14 +10002459 if (buf[0] != '\0')
2460 strlcat(buf, ",", sizeof buf);
Damien Millera8ed44b2003-01-10 09:53:12 +11002461 strlcat(buf, cp, sizeof buf);
Damien Millere247cc42000-05-07 12:03:14 +10002462 }
2463 }
2464 if (buf[0] == '\0')
2465 strlcpy(buf, "notty", sizeof buf);
2466 return buf;
2467}
2468
2469void
2470session_proctitle(Session *s)
2471{
2472 if (s->pw == NULL)
2473 error("no user for session %d", s->self);
2474 else
2475 setproctitle("%s@%s", s->pw->pw_name, session_tty_list());
2476}
2477
Ben Lindstrom768176b2001-06-09 01:29:12 +00002478int
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002479session_setup_x11fwd(struct ssh *ssh, Session *s)
Ben Lindstrom768176b2001-06-09 01:29:12 +00002480{
Ben Lindstrom768176b2001-06-09 01:29:12 +00002481 struct stat st;
Kevin Steves366298c2001-12-19 17:58:01 +00002482 char display[512], auth_display[512];
Damien Millere5c0d522014-07-03 21:24:19 +10002483 char hostname[NI_MAXHOST];
Damien Miller2b9b0452005-07-17 17:19:24 +10002484 u_int i;
Ben Lindstrom768176b2001-06-09 01:29:12 +00002485
djm@openbsd.org7c856852018-03-03 03:15:51 +00002486 if (!auth_opts->permit_x11_forwarding_flag) {
2487 packet_send_debug("X11 forwarding disabled by key options.");
Ben Lindstrom768176b2001-06-09 01:29:12 +00002488 return 0;
2489 }
2490 if (!options.x11_forwarding) {
2491 debug("X11 forwarding disabled in server configuration file.");
2492 return 0;
2493 }
djm@openbsd.org161cf412014-12-22 07:55:51 +00002494 if (options.xauth_location == NULL ||
Ben Lindstrom768176b2001-06-09 01:29:12 +00002495 (stat(options.xauth_location, &st) == -1)) {
djm@openbsd.org7c856852018-03-03 03:15:51 +00002496 packet_send_debug("No xauth program; cannot forward X11.");
Ben Lindstrom768176b2001-06-09 01:29:12 +00002497 return 0;
2498 }
Ben Lindstrom2bcdf062001-06-13 04:41:41 +00002499 if (s->display != NULL) {
Ben Lindstrom768176b2001-06-09 01:29:12 +00002500 debug("X11 display already set.");
2501 return 0;
2502 }
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002503 if (x11_create_display_inet(ssh, options.x11_display_offset,
Ben Lindstroma9d2c892002-06-23 21:48:28 +00002504 options.x11_use_localhost, s->single_connection,
Damien Miller2b9b0452005-07-17 17:19:24 +10002505 &s->display_number, &s->x11_chanids) == -1) {
Ben Lindstrom2bcdf062001-06-13 04:41:41 +00002506 debug("x11_create_display_inet failed.");
Ben Lindstrom768176b2001-06-09 01:29:12 +00002507 return 0;
2508 }
Damien Miller2b9b0452005-07-17 17:19:24 +10002509 for (i = 0; s->x11_chanids[i] != -1; i++) {
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002510 channel_register_cleanup(ssh, s->x11_chanids[i],
Damien Miller39eda6e2005-11-05 14:52:50 +11002511 session_close_single_x11, 0);
Damien Miller2b9b0452005-07-17 17:19:24 +10002512 }
Kevin Steves366298c2001-12-19 17:58:01 +00002513
2514 /* Set up a suitable value for the DISPLAY variable. */
2515 if (gethostname(hostname, sizeof(hostname)) < 0)
2516 fatal("gethostname: %.100s", strerror(errno));
2517 /*
2518 * auth_display must be used as the displayname when the
2519 * authorization entry is added with xauth(1). This will be
2520 * different than the DISPLAY string for localhost displays.
2521 */
Damien Miller95c249f2002-02-05 12:11:34 +11002522 if (options.x11_use_localhost) {
Ben Lindstroma9d2c892002-06-23 21:48:28 +00002523 snprintf(display, sizeof display, "localhost:%u.%u",
Kevin Steves366298c2001-12-19 17:58:01 +00002524 s->display_number, s->screen);
Ben Lindstroma9d2c892002-06-23 21:48:28 +00002525 snprintf(auth_display, sizeof auth_display, "unix:%u.%u",
Damien Miller512bccb2002-02-05 12:11:02 +11002526 s->display_number, s->screen);
Kevin Steves366298c2001-12-19 17:58:01 +00002527 s->display = xstrdup(display);
Damien Miller512bccb2002-02-05 12:11:02 +11002528 s->auth_display = xstrdup(auth_display);
Kevin Steves366298c2001-12-19 17:58:01 +00002529 } else {
2530#ifdef IPADDR_IN_DISPLAY
2531 struct hostent *he;
2532 struct in_addr my_addr;
2533
2534 he = gethostbyname(hostname);
2535 if (he == NULL) {
2536 error("Can't get IP address for X11 DISPLAY.");
2537 packet_send_debug("Can't get IP address for X11 DISPLAY.");
2538 return 0;
2539 }
2540 memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr));
Ben Lindstroma9d2c892002-06-23 21:48:28 +00002541 snprintf(display, sizeof display, "%.50s:%u.%u", inet_ntoa(my_addr),
Kevin Steves366298c2001-12-19 17:58:01 +00002542 s->display_number, s->screen);
2543#else
Ben Lindstroma9d2c892002-06-23 21:48:28 +00002544 snprintf(display, sizeof display, "%.400s:%u.%u", hostname,
Kevin Steves366298c2001-12-19 17:58:01 +00002545 s->display_number, s->screen);
2546#endif
2547 s->display = xstrdup(display);
Damien Miller512bccb2002-02-05 12:11:02 +11002548 s->auth_display = xstrdup(display);
Kevin Steves366298c2001-12-19 17:58:01 +00002549 }
2550
Ben Lindstrom768176b2001-06-09 01:29:12 +00002551 return 1;
2552}
2553
Ben Lindstrombba81212001-06-25 05:01:22 +00002554static void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002555do_authenticated2(struct ssh *ssh, Authctxt *authctxt)
Damien Millerefb4afe2000-04-12 18:45:05 +10002556{
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002557 server_loop2(ssh, authctxt);
Darren Tucker3e33cec2003-10-02 16:12:36 +10002558}
2559
2560void
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002561do_cleanup(struct ssh *ssh, Authctxt *authctxt)
Darren Tucker3e33cec2003-10-02 16:12:36 +10002562{
2563 static int called = 0;
2564
2565 debug("do_cleanup");
2566
2567 /* no cleanup if we're in the child for login shell */
2568 if (is_child)
2569 return;
2570
2571 /* avoid double cleanup */
2572 if (called)
2573 return;
2574 called = 1;
2575
Darren Tucker9142e1c2007-08-16 23:28:04 +10002576 if (authctxt == NULL)
Darren Tucker3e33cec2003-10-02 16:12:36 +10002577 return;
Darren Tucker9142e1c2007-08-16 23:28:04 +10002578
2579#ifdef USE_PAM
2580 if (options.use_pam) {
2581 sshpam_cleanup();
2582 sshpam_thread_cleanup();
2583 }
2584#endif
2585
2586 if (!authctxt->authenticated)
2587 return;
2588
Darren Tucker3e33cec2003-10-02 16:12:36 +10002589#ifdef KRB5
2590 if (options.kerberos_ticket_cleanup &&
2591 authctxt->krb5_ctx)
2592 krb5_cleanup_proc(authctxt);
Darren Tucker0efd1552003-08-26 11:49:55 +10002593#endif
Darren Tucker3e33cec2003-10-02 16:12:36 +10002594
2595#ifdef GSSAPI
markus@openbsd.org6cb6dcf2016-08-13 17:47:40 +00002596 if (options.gss_cleanup_creds)
Darren Tucker3e33cec2003-10-02 16:12:36 +10002597 ssh_gssapi_cleanup_creds();
2598#endif
2599
2600 /* remove agent socket */
2601 auth_sock_cleanup_proc(authctxt->pw);
2602
djm@openbsd.org8f574952017-06-24 06:34:38 +00002603 /* remove userauth info */
2604 if (auth_info_file != NULL) {
2605 temporarily_use_uid(authctxt->pw);
2606 unlink(auth_info_file);
2607 restore_uid();
2608 free(auth_info_file);
2609 auth_info_file = NULL;
2610 }
2611
Darren Tucker3e33cec2003-10-02 16:12:36 +10002612 /*
2613 * Cleanup ptys/utmp only if privsep is disabled,
2614 * or if running in monitor.
2615 */
2616 if (!use_privsep || mm_is_monitor())
djm@openbsd.orgdbee4112017-09-12 06:32:07 +00002617 session_destroy_all(ssh, session_pty_cleanup2);
Damien Millerefb4afe2000-04-12 18:45:05 +10002618}
djm@openbsd.org95767262016-03-07 19:02:43 +00002619
2620/* Return a name for the remote host that fits inside utmp_size */
2621
2622const char *
2623session_get_remote_name_or_ip(struct ssh *ssh, u_int utmp_size, int use_dns)
2624{
2625 const char *remote = "";
2626
2627 if (utmp_size > 0)
2628 remote = auth_get_canonical_hostname(ssh, use_dns);
2629 if (utmp_size == 0 || strlen(remote) > utmp_size)
2630 remote = ssh_remote_ipaddr(ssh);
2631 return remote;
2632}
2633