blob: 71e4fbe7cfc8e5a03ee7ebb9a05ce4d2ce45daf3 [file] [log] [blame]
Damien Miller8853ca52010-06-26 10:00:14 +10001/* $OpenBSD: session.c,v 1.256 2010/06/25 07:20:04 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
Darren Tucker39972492006-07-12 22:22:46 +100049#include <errno.h>
Damien Miller22a29882010-05-10 11:53:54 +100050#include <fcntl.h>
Damien Miller427a1d52006-07-10 20:20:33 +100051#include <grp.h>
Damien Miller6645e7a2006-03-15 14:42:54 +110052#ifdef HAVE_PATHS_H
Damien Miller03e20032006-03-15 11:16:59 +110053#include <paths.h>
Damien Miller6645e7a2006-03-15 14:42:54 +110054#endif
Damien Miller9f2abc42006-07-10 20:53:08 +100055#include <pwd.h>
Damien Miller6ff3cad2006-03-15 11:52:09 +110056#include <signal.h>
Damien Millerded319c2006-09-01 15:38:36 +100057#include <stdarg.h>
Damien Millera7a73ee2006-08-05 11:37:59 +100058#include <stdio.h>
Damien Millere7a1e5c2006-08-05 11:34:19 +100059#include <stdlib.h>
Damien Millere3476ed2006-07-24 14:13:33 +100060#include <string.h>
Damien Miller1cdde6f2006-07-24 14:07:35 +100061#include <unistd.h>
Damien Millerb38eff82000-04-01 11:09:21 +100062
Damien Millerb84886b2008-05-19 15:05:07 +100063#include "openbsd-compat/sys-queue.h"
Damien Millerd7834352006-08-05 12:39:39 +100064#include "xmalloc.h"
Damien Millerb38eff82000-04-01 11:09:21 +100065#include "ssh.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000066#include "ssh1.h"
67#include "ssh2.h"
Ben Lindstromd95c09c2001-02-18 19:13:33 +000068#include "sshpty.h"
Damien Millerb38eff82000-04-01 11:09:21 +100069#include "packet.h"
70#include "buffer.h"
Darren Tucker46bc0752004-05-02 22:11:30 +100071#include "match.h"
Damien Millerb38eff82000-04-01 11:09:21 +100072#include "uidswap.h"
73#include "compat.h"
Ben Lindstromc7637672001-06-09 00:36:26 +000074#include "channels.h"
Damien Millerd7834352006-08-05 12:39:39 +100075#include "key.h"
76#include "cipher.h"
77#ifdef GSSAPI
78#include "ssh-gss.h"
79#endif
80#include "hostfile.h"
Damien Millerefb4afe2000-04-12 18:45:05 +100081#include "auth.h"
Damien Millerf6d9e222000-06-18 14:50:44 +100082#include "auth-options.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000083#include "pathnames.h"
84#include "log.h"
85#include "servconf.h"
Ben Lindstromd95c09c2001-02-18 19:13:33 +000086#include "sshlogin.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000087#include "serverloop.h"
88#include "canohost.h"
Damien Millerd8cb1f12008-02-10 22:40:12 +110089#include "misc.h"
Ben Lindstrom31ca54a2001-02-09 02:11:24 +000090#include "session.h"
Damien Miller9786e6e2005-07-26 21:54:56 +100091#include "kex.h"
Ben Lindstrom7a2073c2002-03-22 02:30:41 +000092#include "monitor_wrap.h"
Damien Millerdfc24252008-02-10 22:29:40 +110093#include "sftp.h"
Damien Millerefb4afe2000-04-12 18:45:05 +100094
Darren Tucker3c78c5e2004-01-23 22:03:10 +110095#if defined(KRB5) && defined(USE_AFS)
Damien Miller8f341f82004-01-21 11:00:46 +110096#include <kafs.h>
97#endif
98
Damien Millerad793d52008-11-03 19:17:57 +110099#define IS_INTERNAL_SFTP(c) \
100 (!strncmp(c, INTERNAL_SFTP_NAME, sizeof(INTERNAL_SFTP_NAME) - 1) && \
101 (c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\0' || \
102 c[sizeof(INTERNAL_SFTP_NAME) - 1] == ' ' || \
103 c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\t'))
104
Damien Millerb38eff82000-04-01 11:09:21 +1000105/* func */
106
107Session *session_new(void);
Damien Miller8853ca52010-06-26 10:00:14 +1000108void session_set_fds(Session *, int, int, int, int, int);
Darren Tucker3e33cec2003-10-02 16:12:36 +1000109void session_pty_cleanup(Session *);
Kevin Steves8f63caa2001-07-04 18:23:02 +0000110void session_proctitle(Session *);
111int session_setup_x11fwd(Session *);
Damien Miller7207f642008-05-19 15:34:50 +1000112int do_exec_pty(Session *, const char *);
113int do_exec_no_pty(Session *, const char *);
114int do_exec(Session *, const char *);
Kevin Steves8f63caa2001-07-04 18:23:02 +0000115void do_login(Session *, const char *);
Kevin Stevesa0957d62001-09-27 19:50:26 +0000116#ifdef LOGIN_NEEDS_UTMPX
117static void do_pre_login(Session *s);
118#endif
Kevin Steves8f63caa2001-07-04 18:23:02 +0000119void do_child(Session *, const char *);
Damien Millercf205e82001-04-16 18:29:15 +1000120void do_motd(void);
Kevin Steves8f63caa2001-07-04 18:23:02 +0000121int check_quietlogin(Session *, const char *);
Damien Millerb38eff82000-04-01 11:09:21 +1000122
Ben Lindstrombba81212001-06-25 05:01:22 +0000123static void do_authenticated1(Authctxt *);
124static void do_authenticated2(Authctxt *);
Kevin Steves8f63caa2001-07-04 18:23:02 +0000125
Ben Lindstrombba81212001-06-25 05:01:22 +0000126static int session_pty_req(Session *);
Ben Lindstromb31783d2001-03-22 02:02:12 +0000127
Damien Millerb38eff82000-04-01 11:09:21 +1000128/* import */
129extern ServerOptions options;
130extern char *__progname;
131extern int log_stderr;
132extern int debug_flag;
Ben Lindstrom46c16222000-12-22 01:43:59 +0000133extern u_int utmp_len;
Damien Miller37023962000-07-11 17:31:38 +1000134extern int startup_pipe;
Ben Lindstrom005dd222001-04-18 15:29:33 +0000135extern void destroy_sensitive_data(void);
Darren Tuckerb9aa0a02003-07-08 22:59:59 +1000136extern Buffer loginmsg;
Damien Miller37023962000-07-11 17:31:38 +1000137
Damien Miller7b28dc52000-09-05 13:34:53 +1100138/* original command from peer. */
Ben Lindstrom0a7ca6c2001-06-21 03:17:42 +0000139const char *original_command = NULL;
Damien Miller7b28dc52000-09-05 13:34:53 +1100140
Damien Millerb38eff82000-04-01 11:09:21 +1000141/* data */
Damien Miller7207f642008-05-19 15:34:50 +1000142static int sessions_first_unused = -1;
143static int sessions_nalloc = 0;
144static Session *sessions = NULL;
Damien Miller15e7d4b2000-09-29 10:57:35 +1100145
Darren Tuckerd6b06a92010-01-08 17:09:11 +1100146#define SUBSYSTEM_NONE 0
147#define SUBSYSTEM_EXT 1
148#define SUBSYSTEM_INT_SFTP 2
149#define SUBSYSTEM_INT_SFTP_ERROR 3
Damien Millerdfc24252008-02-10 22:29:40 +1100150
Damien Millerad833b32000-08-23 10:46:23 +1000151#ifdef HAVE_LOGIN_CAP
Ben Lindstromb481e132002-03-22 01:35:47 +0000152login_cap_t *lc;
Damien Millerad833b32000-08-23 10:46:23 +1000153#endif
154
Darren Tucker3e33cec2003-10-02 16:12:36 +1000155static int is_child = 0;
156
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000157/* Name and directory of socket for authentication agent forwarding. */
158static char *auth_sock_name = NULL;
159static char *auth_sock_dir = NULL;
160
161/* removes the agent forwarding socket */
162
163static void
Darren Tucker3e33cec2003-10-02 16:12:36 +1000164auth_sock_cleanup_proc(struct passwd *pw)
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000165{
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000166 if (auth_sock_name != NULL) {
167 temporarily_use_uid(pw);
168 unlink(auth_sock_name);
169 rmdir(auth_sock_dir);
170 auth_sock_name = NULL;
171 restore_uid();
172 }
173}
174
175static int
176auth_input_request_forwarding(struct passwd * pw)
177{
178 Channel *nc;
Damien Miller7207f642008-05-19 15:34:50 +1000179 int sock = -1;
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000180 struct sockaddr_un sunaddr;
181
182 if (auth_sock_name != NULL) {
183 error("authentication forwarding requested twice.");
184 return 0;
185 }
186
187 /* Temporarily drop privileged uid for mkdir/bind. */
188 temporarily_use_uid(pw);
189
190 /* Allocate a buffer for the socket name, and format the name. */
Damien Miller7207f642008-05-19 15:34:50 +1000191 auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX");
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000192
193 /* Create private directory for socket */
194 if (mkdtemp(auth_sock_dir) == NULL) {
195 packet_send_debug("Agent forwarding disabled: "
196 "mkdtemp() failed: %.100s", strerror(errno));
197 restore_uid();
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000198 xfree(auth_sock_dir);
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000199 auth_sock_dir = NULL;
Damien Miller7207f642008-05-19 15:34:50 +1000200 goto authsock_err;
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000201 }
Damien Miller7207f642008-05-19 15:34:50 +1000202
203 xasprintf(&auth_sock_name, "%s/agent.%ld",
204 auth_sock_dir, (long) getpid());
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000205
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000206 /* Create the socket. */
207 sock = socket(AF_UNIX, SOCK_STREAM, 0);
Damien Miller7207f642008-05-19 15:34:50 +1000208 if (sock < 0) {
209 error("socket: %.100s", strerror(errno));
210 restore_uid();
211 goto authsock_err;
212 }
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000213
214 /* Bind it to the name. */
215 memset(&sunaddr, 0, sizeof(sunaddr));
216 sunaddr.sun_family = AF_UNIX;
217 strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path));
218
Damien Miller7207f642008-05-19 15:34:50 +1000219 if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
220 error("bind: %.100s", strerror(errno));
221 restore_uid();
222 goto authsock_err;
223 }
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000224
225 /* Restore the privileged uid. */
226 restore_uid();
227
228 /* Start listening on the socket. */
Damien Miller7207f642008-05-19 15:34:50 +1000229 if (listen(sock, SSH_LISTEN_BACKLOG) < 0) {
230 error("listen: %.100s", strerror(errno));
231 goto authsock_err;
232 }
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000233
234 /* Allocate a channel for the authentication agent socket. */
235 nc = channel_new("auth socket",
236 SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,
237 CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
Damien Millerb1ca8bb2003-05-14 13:45:42 +1000238 0, "auth socket", 1);
Damien Millera1c1b6c2009-01-28 16:29:49 +1100239 nc->path = xstrdup(auth_sock_name);
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000240 return 1;
Damien Miller7207f642008-05-19 15:34:50 +1000241
242 authsock_err:
243 if (auth_sock_name != NULL)
244 xfree(auth_sock_name);
245 if (auth_sock_dir != NULL) {
246 rmdir(auth_sock_dir);
247 xfree(auth_sock_dir);
248 }
249 if (sock != -1)
250 close(sock);
251 auth_sock_name = NULL;
252 auth_sock_dir = NULL;
253 return 0;
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000254}
255
Darren Tucker1921ed92004-02-10 13:23:28 +1100256static void
257display_loginmsg(void)
258{
Damien Miller46d38de2005-07-17 17:02:09 +1000259 if (buffer_len(&loginmsg) > 0) {
260 buffer_append(&loginmsg, "\0", 1);
261 printf("%s", (char *)buffer_ptr(&loginmsg));
262 buffer_clear(&loginmsg);
263 }
Darren Tucker1921ed92004-02-10 13:23:28 +1100264}
Ben Lindstrom8bb6f362002-06-11 15:59:02 +0000265
Ben Lindstromb31783d2001-03-22 02:02:12 +0000266void
267do_authenticated(Authctxt *authctxt)
268{
Damien Miller97f39ae2003-02-24 11:57:01 +1100269 setproctitle("%s", authctxt->pw->pw_name);
270
Ben Lindstromb31783d2001-03-22 02:02:12 +0000271 /* setup the channel layer */
272 if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
273 channel_permit_all_opens();
274
Darren Tuckercd70e1b2010-03-07 23:05:17 +1100275 auth_debug_send();
276
Ben Lindstromb31783d2001-03-22 02:02:12 +0000277 if (compat20)
278 do_authenticated2(authctxt);
279 else
280 do_authenticated1(authctxt);
Ben Lindstrom838394c2001-06-09 01:11:59 +0000281
Darren Tucker3e33cec2003-10-02 16:12:36 +1000282 do_cleanup(authctxt);
Ben Lindstromb31783d2001-03-22 02:02:12 +0000283}
284
Damien Millerb38eff82000-04-01 11:09:21 +1000285/*
Damien Millerb38eff82000-04-01 11:09:21 +1000286 * Prepares for an interactive session. This is called after the user has
287 * been successfully authenticated. During this message exchange, pseudo
288 * terminals are allocated, X11, TCP/IP, and authentication agent forwardings
289 * are requested, etc.
290 */
Ben Lindstrombba81212001-06-25 05:01:22 +0000291static void
Ben Lindstromb31783d2001-03-22 02:02:12 +0000292do_authenticated1(Authctxt *authctxt)
Damien Millerb38eff82000-04-01 11:09:21 +1000293{
294 Session *s;
Damien Millerb38eff82000-04-01 11:09:21 +1000295 char *command;
Damien Millerdff50992002-01-22 23:16:32 +1100296 int success, type, screen_flag;
Ben Lindstrome23f4a32002-06-23 21:40:16 +0000297 int enable_compression_after_reply = 0;
298 u_int proto_len, data_len, dlen, compression_level = 0;
Damien Millerb38eff82000-04-01 11:09:21 +1000299
300 s = session_new();
Darren Tucker172a5e82005-01-20 10:55:46 +1100301 if (s == NULL) {
302 error("no more sessions");
303 return;
304 }
Ben Lindstromec95ed92001-07-04 04:21:14 +0000305 s->authctxt = authctxt;
Ben Lindstromb31783d2001-03-22 02:02:12 +0000306 s->pw = authctxt->pw;
Damien Millerad833b32000-08-23 10:46:23 +1000307
Damien Millerb38eff82000-04-01 11:09:21 +1000308 /*
309 * We stay in this loop until the client requests to execute a shell
310 * or a command.
311 */
312 for (;;) {
Ben Lindstromb31783d2001-03-22 02:02:12 +0000313 success = 0;
Damien Millerb38eff82000-04-01 11:09:21 +1000314
315 /* Get a packet from the client. */
Damien Millerdff50992002-01-22 23:16:32 +1100316 type = packet_read();
Damien Millerb38eff82000-04-01 11:09:21 +1000317
318 /* Process the packet. */
319 switch (type) {
320 case SSH_CMSG_REQUEST_COMPRESSION:
Damien Millerb38eff82000-04-01 11:09:21 +1000321 compression_level = packet_get_int();
Damien Miller48b03fc2002-01-22 23:11:40 +1100322 packet_check_eom();
Damien Millerb38eff82000-04-01 11:09:21 +1000323 if (compression_level < 1 || compression_level > 9) {
Darren Tucker5cb30ad2004-08-12 22:40:24 +1000324 packet_send_debug("Received invalid compression level %d.",
Damien Miller9f0f5c62001-12-21 14:45:46 +1100325 compression_level);
Damien Millerb38eff82000-04-01 11:09:21 +1000326 break;
327 }
Damien Miller9786e6e2005-07-26 21:54:56 +1000328 if (options.compression == COMP_NONE) {
Ben Lindstrom23e0f662002-06-21 01:09:47 +0000329 debug2("compression disabled");
330 break;
331 }
Damien Millerb38eff82000-04-01 11:09:21 +1000332 /* Enable compression after we have responded with SUCCESS. */
333 enable_compression_after_reply = 1;
334 success = 1;
335 break;
336
337 case SSH_CMSG_REQUEST_PTY:
Ben Lindstrom49c12602001-06-13 04:37:36 +0000338 success = session_pty_req(s);
Damien Millerb38eff82000-04-01 11:09:21 +1000339 break;
340
341 case SSH_CMSG_X11_REQUEST_FORWARDING:
Damien Millerb38eff82000-04-01 11:09:21 +1000342 s->auth_proto = packet_get_string(&proto_len);
343 s->auth_data = packet_get_string(&data_len);
Damien Millerb38eff82000-04-01 11:09:21 +1000344
Ben Lindstrom7603b2d2001-02-26 20:13:32 +0000345 screen_flag = packet_get_protocol_flags() &
346 SSH_PROTOFLAG_SCREEN_NUMBER;
347 debug2("SSH_PROTOFLAG_SCREEN_NUMBER: %d", screen_flag);
348
349 if (packet_remaining() == 4) {
350 if (!screen_flag)
351 debug2("Buggy client: "
352 "X11 screen flag missing");
Damien Millerb38eff82000-04-01 11:09:21 +1000353 s->screen = packet_get_int();
Ben Lindstrom8dcdeb82001-02-16 16:02:14 +0000354 } else {
Damien Millerb38eff82000-04-01 11:09:21 +1000355 s->screen = 0;
Ben Lindstrom8dcdeb82001-02-16 16:02:14 +0000356 }
Damien Miller48b03fc2002-01-22 23:11:40 +1100357 packet_check_eom();
Ben Lindstrom768176b2001-06-09 01:29:12 +0000358 success = session_setup_x11fwd(s);
359 if (!success) {
360 xfree(s->auth_proto);
361 xfree(s->auth_data);
Ben Lindstrom88259fb2001-06-12 00:21:34 +0000362 s->auth_proto = NULL;
363 s->auth_data = NULL;
Damien Millerb38eff82000-04-01 11:09:21 +1000364 }
Damien Millerb38eff82000-04-01 11:09:21 +1000365 break;
Damien Millerb38eff82000-04-01 11:09:21 +1000366
367 case SSH_CMSG_AGENT_REQUEST_FORWARDING:
Damien Miller4f755cd2008-05-19 14:57:41 +1000368 if (!options.allow_agent_forwarding ||
369 no_agent_forwarding_flag || compat13) {
Damien Millerb38eff82000-04-01 11:09:21 +1000370 debug("Authentication agent forwarding not permitted for this authentication.");
371 break;
372 }
373 debug("Received authentication agent forwarding request.");
Ben Lindstromb31783d2001-03-22 02:02:12 +0000374 success = auth_input_request_forwarding(s->pw);
Damien Millerb38eff82000-04-01 11:09:21 +1000375 break;
376
377 case SSH_CMSG_PORT_FORWARD_REQUEST:
378 if (no_port_forwarding_flag) {
379 debug("Port forwarding not permitted for this authentication.");
380 break;
381 }
Damien Miller50a41ed2000-10-16 12:14:42 +1100382 if (!options.allow_tcp_forwarding) {
383 debug("Port forwarding not permitted.");
384 break;
385 }
Damien Millerb38eff82000-04-01 11:09:21 +1000386 debug("Received TCP/IP port forwarding request.");
Darren Tuckere7d4b192006-07-12 22:17:10 +1000387 if (channel_input_port_forward_request(s->pw->pw_uid == 0,
388 options.gateway_ports) < 0) {
389 debug("Port forwarding failed.");
390 break;
391 }
Damien Millerb38eff82000-04-01 11:09:21 +1000392 success = 1;
393 break;
394
395 case SSH_CMSG_MAX_PACKET_SIZE:
396 if (packet_set_maxsize(packet_get_int()) > 0)
397 success = 1;
398 break;
Damien Miller9f0f5c62001-12-21 14:45:46 +1100399
Damien Millerb38eff82000-04-01 11:09:21 +1000400 case SSH_CMSG_EXEC_SHELL:
401 case SSH_CMSG_EXEC_CMD:
Damien Millerb38eff82000-04-01 11:09:21 +1000402 if (type == SSH_CMSG_EXEC_CMD) {
403 command = packet_get_string(&dlen);
404 debug("Exec command '%.500s'", command);
Damien Miller7207f642008-05-19 15:34:50 +1000405 if (do_exec(s, command) != 0)
406 packet_disconnect(
407 "command execution failed");
Ben Lindstrom0a7ca6c2001-06-21 03:17:42 +0000408 xfree(command);
Damien Millerb38eff82000-04-01 11:09:21 +1000409 } else {
Damien Miller7207f642008-05-19 15:34:50 +1000410 if (do_exec(s, NULL) != 0)
411 packet_disconnect(
412 "shell execution failed");
Damien Millerb38eff82000-04-01 11:09:21 +1000413 }
Damien Miller48b03fc2002-01-22 23:11:40 +1100414 packet_check_eom();
Ben Lindstromcb3929d2001-06-09 01:34:15 +0000415 session_close(s);
Damien Millerb38eff82000-04-01 11:09:21 +1000416 return;
417
418 default:
419 /*
420 * Any unknown messages in this phase are ignored,
421 * and a failure message is returned.
422 */
Damien Miller996acd22003-04-09 20:59:48 +1000423 logit("Unknown packet type received after authentication: %d", type);
Damien Millerb38eff82000-04-01 11:09:21 +1000424 }
425 packet_start(success ? SSH_SMSG_SUCCESS : SSH_SMSG_FAILURE);
426 packet_send();
427 packet_write_wait();
428
429 /* Enable compression now that we have replied if appropriate. */
430 if (enable_compression_after_reply) {
431 enable_compression_after_reply = 0;
432 packet_start_compression(compression_level);
433 }
434 }
435}
436
Damien Miller7207f642008-05-19 15:34:50 +1000437#define USE_PIPES
Damien Millerb38eff82000-04-01 11:09:21 +1000438/*
439 * This is called to fork and execute a command when we have no tty. This
440 * will call do_child from the child, and server_loop from the parent after
441 * setting up file descriptors and such.
442 */
Damien Miller7207f642008-05-19 15:34:50 +1000443int
Ben Lindstromb4c961d2001-03-22 01:25:37 +0000444do_exec_no_pty(Session *s, const char *command)
Damien Millerb38eff82000-04-01 11:09:21 +1000445{
Ben Lindstromce0f6342002-06-11 16:42:49 +0000446 pid_t pid;
Damien Millerb38eff82000-04-01 11:09:21 +1000447
448#ifdef USE_PIPES
449 int pin[2], pout[2], perr[2];
Damien Miller7207f642008-05-19 15:34:50 +1000450
Damien Miller22a29882010-05-10 11:53:54 +1000451 if (s == NULL)
452 fatal("do_exec_no_pty: no session");
453
Damien Millerb38eff82000-04-01 11:09:21 +1000454 /* Allocate pipes for communicating with the program. */
Damien Miller7207f642008-05-19 15:34:50 +1000455 if (pipe(pin) < 0) {
456 error("%s: pipe in: %.100s", __func__, strerror(errno));
457 return -1;
458 }
459 if (pipe(pout) < 0) {
460 error("%s: pipe out: %.100s", __func__, strerror(errno));
461 close(pin[0]);
462 close(pin[1]);
463 return -1;
464 }
Damien Miller8853ca52010-06-26 10:00:14 +1000465 if (pipe(perr) < 0) {
466 error("%s: pipe err: %.100s", __func__,
467 strerror(errno));
468 close(pin[0]);
469 close(pin[1]);
470 close(pout[0]);
471 close(pout[1]);
472 return -1;
Damien Miller7207f642008-05-19 15:34:50 +1000473 }
474#else
Damien Millerb38eff82000-04-01 11:09:21 +1000475 int inout[2], err[2];
Damien Miller7207f642008-05-19 15:34:50 +1000476
Damien Miller22a29882010-05-10 11:53:54 +1000477 if (s == NULL)
478 fatal("do_exec_no_pty: no session");
479
Damien Millerb38eff82000-04-01 11:09:21 +1000480 /* Uses socket pairs to communicate with the program. */
Damien Miller7207f642008-05-19 15:34:50 +1000481 if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0) {
482 error("%s: socketpair #1: %.100s", __func__, strerror(errno));
483 return -1;
484 }
Damien Miller8853ca52010-06-26 10:00:14 +1000485 if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) {
486 error("%s: socketpair #2: %.100s", __func__,
487 strerror(errno));
488 close(inout[0]);
489 close(inout[1]);
490 return -1;
Damien Miller7207f642008-05-19 15:34:50 +1000491 }
492#endif
493
Damien Millere247cc42000-05-07 12:03:14 +1000494 session_proctitle(s);
Damien Millerb38eff82000-04-01 11:09:21 +1000495
Damien Millerb38eff82000-04-01 11:09:21 +1000496 /* Fork the child. */
Damien Miller7207f642008-05-19 15:34:50 +1000497 switch ((pid = fork())) {
498 case -1:
499 error("%s: fork: %.100s", __func__, strerror(errno));
500#ifdef USE_PIPES
501 close(pin[0]);
502 close(pin[1]);
503 close(pout[0]);
504 close(pout[1]);
Damien Miller8853ca52010-06-26 10:00:14 +1000505 close(perr[0]);
Damien Miller7207f642008-05-19 15:34:50 +1000506 close(perr[1]);
507#else
508 close(inout[0]);
509 close(inout[1]);
510 close(err[0]);
Damien Miller8853ca52010-06-26 10:00:14 +1000511 close(err[1]);
Damien Miller7207f642008-05-19 15:34:50 +1000512#endif
513 return -1;
514 case 0:
Darren Tucker3e33cec2003-10-02 16:12:36 +1000515 is_child = 1;
Ben Lindstrom264ee302002-07-23 21:01:56 +0000516
Damien Millerb38eff82000-04-01 11:09:21 +1000517 /* Child. Reinitialize the log since the pid has changed. */
Damien Miller7207f642008-05-19 15:34:50 +1000518 log_init(__progname, options.log_level,
519 options.log_facility, log_stderr);
Damien Millerb38eff82000-04-01 11:09:21 +1000520
521 /*
522 * Create a new session and process group since the 4.4BSD
523 * setlogin() affects the entire process group.
524 */
525 if (setsid() < 0)
526 error("setsid failed: %.100s", strerror(errno));
527
528#ifdef USE_PIPES
529 /*
530 * Redirect stdin. We close the parent side of the socket
531 * pair, and make the child side the standard input.
532 */
533 close(pin[1]);
534 if (dup2(pin[0], 0) < 0)
535 perror("dup2 stdin");
536 close(pin[0]);
537
538 /* Redirect stdout. */
539 close(pout[0]);
540 if (dup2(pout[1], 1) < 0)
541 perror("dup2 stdout");
542 close(pout[1]);
543
544 /* Redirect stderr. */
Damien Miller8853ca52010-06-26 10:00:14 +1000545 close(perr[0]);
Damien Millerb38eff82000-04-01 11:09:21 +1000546 if (dup2(perr[1], 2) < 0)
547 perror("dup2 stderr");
548 close(perr[1]);
Damien Miller7207f642008-05-19 15:34:50 +1000549#else
Damien Millerb38eff82000-04-01 11:09:21 +1000550 /*
551 * Redirect stdin, stdout, and stderr. Stdin and stdout will
552 * use the same socket, as some programs (particularly rdist)
553 * seem to depend on it.
554 */
555 close(inout[1]);
Damien Miller8853ca52010-06-26 10:00:14 +1000556 close(err[1]);
Damien Millerb38eff82000-04-01 11:09:21 +1000557 if (dup2(inout[0], 0) < 0) /* stdin */
558 perror("dup2 stdin");
Damien Miller7207f642008-05-19 15:34:50 +1000559 if (dup2(inout[0], 1) < 0) /* stdout (same as stdin) */
Damien Millerb38eff82000-04-01 11:09:21 +1000560 perror("dup2 stdout");
Damien Miller7207f642008-05-19 15:34:50 +1000561 close(inout[0]);
Damien Millerb38eff82000-04-01 11:09:21 +1000562 if (dup2(err[0], 2) < 0) /* stderr */
563 perror("dup2 stderr");
Damien Miller7207f642008-05-19 15:34:50 +1000564 close(err[0]);
565#endif
566
Damien Millerb38eff82000-04-01 11:09:21 +1000567
Tim Rice81ed5182002-09-25 17:38:46 -0700568#ifdef _UNICOS
569 cray_init_job(s->pw); /* set up cray jid and tmpdir */
570#endif
571
Damien Millerb38eff82000-04-01 11:09:21 +1000572 /* Do processing for the child (exec command etc). */
Ben Lindstrom86fe8682001-03-17 00:32:57 +0000573 do_child(s, command);
Damien Millerb38eff82000-04-01 11:09:21 +1000574 /* NOTREACHED */
Damien Miller7207f642008-05-19 15:34:50 +1000575 default:
576 break;
Damien Millerb38eff82000-04-01 11:09:21 +1000577 }
Damien Miller7207f642008-05-19 15:34:50 +1000578
Tim Rice81ed5182002-09-25 17:38:46 -0700579#ifdef _UNICOS
580 signal(WJSIGNAL, cray_job_termination_handler);
581#endif /* _UNICOS */
Damien Millerbac2d8a2000-09-05 16:13:06 +1100582#ifdef HAVE_CYGWIN
Darren Tucker9d86e5d2009-03-08 11:40:27 +1100583 cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
Damien Millerbac2d8a2000-09-05 16:13:06 +1100584#endif
Damien Miller7207f642008-05-19 15:34:50 +1000585
Damien Millerb38eff82000-04-01 11:09:21 +1000586 s->pid = pid;
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000587 /* Set interactive/non-interactive mode. */
588 packet_set_interactive(s->display != NULL);
Damien Miller7207f642008-05-19 15:34:50 +1000589
590 /*
591 * Clear loginmsg, since it's the child's responsibility to display
592 * it to the user, otherwise multiple sessions may accumulate
593 * multiple copies of the login messages.
594 */
595 buffer_clear(&loginmsg);
596
Damien Millerb38eff82000-04-01 11:09:21 +1000597#ifdef USE_PIPES
598 /* We are the parent. Close the child sides of the pipes. */
599 close(pin[0]);
600 close(pout[1]);
601 close(perr[1]);
602
Damien Millerefb4afe2000-04-12 18:45:05 +1000603 if (compat20) {
Damien Miller8853ca52010-06-26 10:00:14 +1000604 session_set_fds(s, pin[1], pout[0], perr[0],
605 s->is_subsystem, 0);
Damien Millerefb4afe2000-04-12 18:45:05 +1000606 } else {
607 /* Enter the interactive session. */
608 server_loop(pid, pin[1], pout[0], perr[0]);
Ben Lindstromfc9b07d2001-03-22 01:27:23 +0000609 /* server_loop has closed pin[1], pout[0], and perr[0]. */
Damien Millerefb4afe2000-04-12 18:45:05 +1000610 }
Damien Miller7207f642008-05-19 15:34:50 +1000611#else
Damien Millerb38eff82000-04-01 11:09:21 +1000612 /* We are the parent. Close the child sides of the socket pairs. */
613 close(inout[0]);
614 close(err[0]);
615
616 /*
617 * Enter the interactive session. Note: server_loop must be able to
618 * handle the case that fdin and fdout are the same.
619 */
Damien Millerefb4afe2000-04-12 18:45:05 +1000620 if (compat20) {
Damien Miller8853ca52010-06-26 10:00:14 +1000621 session_set_fds(s, inout[1], inout[1], err[1],
622 s->is_subsystem, 0);
Damien Millerefb4afe2000-04-12 18:45:05 +1000623 } else {
624 server_loop(pid, inout[1], inout[1], err[1]);
625 /* server_loop has closed inout[1] and err[1]. */
626 }
Damien Miller7207f642008-05-19 15:34:50 +1000627#endif
628 return 0;
Damien Millerb38eff82000-04-01 11:09:21 +1000629}
630
631/*
632 * This is called to fork and execute a command when we have a tty. This
633 * will call do_child from the child, and server_loop from the parent after
634 * setting up file descriptors, controlling tty, updating wtmp, utmp,
635 * lastlog, and other such operations.
636 */
Damien Miller7207f642008-05-19 15:34:50 +1000637int
Ben Lindstromb4c961d2001-03-22 01:25:37 +0000638do_exec_pty(Session *s, const char *command)
Damien Millerb38eff82000-04-01 11:09:21 +1000639{
Damien Millerb38eff82000-04-01 11:09:21 +1000640 int fdout, ptyfd, ttyfd, ptymaster;
Damien Millerb38eff82000-04-01 11:09:21 +1000641 pid_t pid;
Damien Millerb38eff82000-04-01 11:09:21 +1000642
643 if (s == NULL)
644 fatal("do_exec_pty: no session");
645 ptyfd = s->ptyfd;
646 ttyfd = s->ttyfd;
647
Damien Miller7207f642008-05-19 15:34:50 +1000648 /*
649 * Create another descriptor of the pty master side for use as the
650 * standard input. We could use the original descriptor, but this
651 * simplifies code in server_loop. The descriptor is bidirectional.
652 * Do this before forking (and cleanup in the child) so as to
653 * detect and gracefully fail out-of-fd conditions.
654 */
655 if ((fdout = dup(ptyfd)) < 0) {
656 error("%s: dup #1: %s", __func__, strerror(errno));
657 close(ttyfd);
658 close(ptyfd);
659 return -1;
660 }
661 /* we keep a reference to the pty master */
662 if ((ptymaster = dup(ptyfd)) < 0) {
663 error("%s: dup #2: %s", __func__, strerror(errno));
664 close(ttyfd);
665 close(ptyfd);
666 close(fdout);
667 return -1;
668 }
669
Damien Millerb38eff82000-04-01 11:09:21 +1000670 /* Fork the child. */
Damien Miller7207f642008-05-19 15:34:50 +1000671 switch ((pid = fork())) {
672 case -1:
673 error("%s: fork: %.100s", __func__, strerror(errno));
674 close(fdout);
675 close(ptymaster);
676 close(ttyfd);
677 close(ptyfd);
678 return -1;
679 case 0:
Darren Tucker3e33cec2003-10-02 16:12:36 +1000680 is_child = 1;
Ben Lindstrombddd5512001-07-04 04:53:53 +0000681
Damien Miller7207f642008-05-19 15:34:50 +1000682 close(fdout);
683 close(ptymaster);
684
Damien Miller942da032000-08-18 13:59:06 +1000685 /* Child. Reinitialize the log because the pid has changed. */
Damien Miller7207f642008-05-19 15:34:50 +1000686 log_init(__progname, options.log_level,
687 options.log_facility, log_stderr);
Damien Millerb38eff82000-04-01 11:09:21 +1000688 /* Close the master side of the pseudo tty. */
689 close(ptyfd);
690
691 /* Make the pseudo tty our controlling tty. */
692 pty_make_controlling_tty(&ttyfd, s->tty);
693
Damien Miller9c751422001-10-10 15:02:46 +1000694 /* Redirect stdin/stdout/stderr from the pseudo tty. */
695 if (dup2(ttyfd, 0) < 0)
696 error("dup2 stdin: %s", strerror(errno));
697 if (dup2(ttyfd, 1) < 0)
698 error("dup2 stdout: %s", strerror(errno));
699 if (dup2(ttyfd, 2) < 0)
700 error("dup2 stderr: %s", strerror(errno));
Damien Millerb38eff82000-04-01 11:09:21 +1000701
702 /* Close the extra descriptor for the pseudo tty. */
703 close(ttyfd);
704
Damien Miller942da032000-08-18 13:59:06 +1000705 /* record login, etc. similar to login(1) */
Damien Miller364a9bd2001-04-16 18:37:05 +1000706#ifndef HAVE_OSF_SIA
Tim Rice81ed5182002-09-25 17:38:46 -0700707 if (!(options.use_login && command == NULL)) {
708#ifdef _UNICOS
709 cray_init_job(s->pw); /* set up cray jid and tmpdir */
710#endif /* _UNICOS */
Damien Miller69b69aa2000-10-28 14:19:58 +1100711 do_login(s, command);
Tim Rice81ed5182002-09-25 17:38:46 -0700712 }
Ben Lindstrom97c677d2001-05-08 20:33:05 +0000713# ifdef LOGIN_NEEDS_UTMPX
714 else
715 do_pre_login(s);
716# endif
Damien Miller364a9bd2001-04-16 18:37:05 +1000717#endif
Damien Miller7207f642008-05-19 15:34:50 +1000718 /*
719 * Do common processing for the child, such as execing
720 * the command.
721 */
Darren Tucker43e7a352009-06-21 19:50:08 +1000722 do_child(s, command);
723 /* NOTREACHED */
Damien Miller7207f642008-05-19 15:34:50 +1000724 default:
725 break;
Damien Millerb38eff82000-04-01 11:09:21 +1000726 }
Damien Miller7207f642008-05-19 15:34:50 +1000727
Tim Rice81ed5182002-09-25 17:38:46 -0700728#ifdef _UNICOS
729 signal(WJSIGNAL, cray_job_termination_handler);
730#endif /* _UNICOS */
Damien Millerbac2d8a2000-09-05 16:13:06 +1100731#ifdef HAVE_CYGWIN
Darren Tucker9d86e5d2009-03-08 11:40:27 +1100732 cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
Damien Millerbac2d8a2000-09-05 16:13:06 +1100733#endif
Damien Miller7207f642008-05-19 15:34:50 +1000734
Damien Millerb38eff82000-04-01 11:09:21 +1000735 s->pid = pid;
736
737 /* Parent. Close the slave side of the pseudo tty. */
738 close(ttyfd);
739
Damien Millerb38eff82000-04-01 11:09:21 +1000740 /* Enter interactive session. */
Damien Miller7207f642008-05-19 15:34:50 +1000741 s->ptymaster = ptymaster;
Ben Lindstrombf555ba2001-01-18 02:04:35 +0000742 packet_set_interactive(1);
Damien Millerefb4afe2000-04-12 18:45:05 +1000743 if (compat20) {
Damien Miller8853ca52010-06-26 10:00:14 +1000744 session_set_fds(s, ptyfd, fdout, -1, 1, 1);
Damien Millerefb4afe2000-04-12 18:45:05 +1000745 } else {
746 server_loop(pid, ptyfd, fdout, -1);
747 /* server_loop _has_ closed ptyfd and fdout. */
Damien Millerefb4afe2000-04-12 18:45:05 +1000748 }
Damien Miller7207f642008-05-19 15:34:50 +1000749 return 0;
Damien Millerb38eff82000-04-01 11:09:21 +1000750}
751
Ben Lindstrom97c677d2001-05-08 20:33:05 +0000752#ifdef LOGIN_NEEDS_UTMPX
Damien Miller599d8eb2001-09-15 12:25:53 +1000753static void
Ben Lindstrom97c677d2001-05-08 20:33:05 +0000754do_pre_login(Session *s)
755{
756 socklen_t fromlen;
757 struct sockaddr_storage from;
758 pid_t pid = getpid();
759
760 /*
761 * Get IP address of client. If the connection is not a socket, let
762 * the address be 0.0.0.0.
763 */
764 memset(&from, 0, sizeof(from));
Damien Millerebc23062002-09-04 16:45:09 +1000765 fromlen = sizeof(from);
Ben Lindstrom97c677d2001-05-08 20:33:05 +0000766 if (packet_connection_is_on_socket()) {
Ben Lindstrom97c677d2001-05-08 20:33:05 +0000767 if (getpeername(packet_get_connection_in(),
Damien Miller90967402006-03-26 14:07:26 +1100768 (struct sockaddr *)&from, &fromlen) < 0) {
Ben Lindstrom97c677d2001-05-08 20:33:05 +0000769 debug("getpeername: %.100s", strerror(errno));
Darren Tucker3e33cec2003-10-02 16:12:36 +1000770 cleanup_exit(255);
Ben Lindstrom97c677d2001-05-08 20:33:05 +0000771 }
772 }
773
774 record_utmp_only(pid, s->tty, s->pw->pw_name,
Damien Miller3a961dc2003-06-03 10:25:48 +1000775 get_remote_name_or_ip(utmp_len, options.use_dns),
Kevin Steves678ee512003-01-01 23:43:55 +0000776 (struct sockaddr *)&from, fromlen);
Ben Lindstrom97c677d2001-05-08 20:33:05 +0000777}
778#endif
779
Ben Lindstromc85ab8a2001-06-21 03:13:10 +0000780/*
781 * This is called to fork and execute a command. If another command is
782 * to be forced, execute that instead.
783 */
Damien Miller7207f642008-05-19 15:34:50 +1000784int
Ben Lindstromc85ab8a2001-06-21 03:13:10 +0000785do_exec(Session *s, const char *command)
786{
Damien Miller7207f642008-05-19 15:34:50 +1000787 int ret;
788
Damien Millere2754432006-07-24 14:06:47 +1000789 if (options.adm_forced_command) {
790 original_command = command;
791 command = options.adm_forced_command;
Darren Tuckerd6b06a92010-01-08 17:09:11 +1100792 if (IS_INTERNAL_SFTP(command)) {
793 s->is_subsystem = s->is_subsystem ?
794 SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR;
795 } else if (s->is_subsystem)
Damien Millerdfc24252008-02-10 22:29:40 +1100796 s->is_subsystem = SUBSYSTEM_EXT;
Damien Millere2754432006-07-24 14:06:47 +1000797 debug("Forced command (config) '%.900s'", command);
798 } else if (forced_command) {
Ben Lindstromc85ab8a2001-06-21 03:13:10 +0000799 original_command = command;
800 command = forced_command;
Darren Tuckerd6b06a92010-01-08 17:09:11 +1100801 if (IS_INTERNAL_SFTP(command)) {
802 s->is_subsystem = s->is_subsystem ?
803 SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR;
804 } else if (s->is_subsystem)
Damien Millerdfc24252008-02-10 22:29:40 +1100805 s->is_subsystem = SUBSYSTEM_EXT;
Damien Millere2754432006-07-24 14:06:47 +1000806 debug("Forced command (key option) '%.900s'", command);
Ben Lindstromc85ab8a2001-06-21 03:13:10 +0000807 }
808
Darren Tucker2e0cf0d2005-02-08 21:52:47 +1100809#ifdef SSH_AUDIT_EVENTS
Darren Tucker269a1ea2005-02-03 00:20:53 +1100810 if (command != NULL)
811 PRIVSEP(audit_run_command(command));
812 else if (s->ttyfd == -1) {
813 char *shell = s->pw->pw_shell;
814
815 if (shell[0] == '\0') /* empty shell means /bin/sh */
816 shell =_PATH_BSHELL;
817 PRIVSEP(audit_run_command(shell));
818 }
819#endif
Ben Lindstromc85ab8a2001-06-21 03:13:10 +0000820 if (s->ttyfd != -1)
Damien Miller7207f642008-05-19 15:34:50 +1000821 ret = do_exec_pty(s, command);
Ben Lindstromc85ab8a2001-06-21 03:13:10 +0000822 else
Damien Miller7207f642008-05-19 15:34:50 +1000823 ret = do_exec_no_pty(s, command);
Ben Lindstromc85ab8a2001-06-21 03:13:10 +0000824
Ben Lindstrom0a7ca6c2001-06-21 03:17:42 +0000825 original_command = NULL;
Ben Lindstromc85ab8a2001-06-21 03:13:10 +0000826
Darren Tucker09991742004-07-17 17:05:14 +1000827 /*
828 * Clear loginmsg: it's the child's responsibility to display
829 * it to the user, otherwise multiple sessions may accumulate
830 * multiple copies of the login messages.
831 */
832 buffer_clear(&loginmsg);
Damien Miller7207f642008-05-19 15:34:50 +1000833
834 return ret;
Darren Tucker09991742004-07-17 17:05:14 +1000835}
Ben Lindstrom4e97e852002-02-19 21:50:43 +0000836
Damien Miller942da032000-08-18 13:59:06 +1000837/* administrative, login(1)-like work */
838void
Damien Miller69b69aa2000-10-28 14:19:58 +1100839do_login(Session *s, const char *command)
Damien Miller942da032000-08-18 13:59:06 +1000840{
Damien Miller942da032000-08-18 13:59:06 +1000841 socklen_t fromlen;
842 struct sockaddr_storage from;
Damien Miller942da032000-08-18 13:59:06 +1000843 struct passwd * pw = s->pw;
844 pid_t pid = getpid();
845
846 /*
847 * Get IP address of client. If the connection is not a socket, let
848 * the address be 0.0.0.0.
849 */
850 memset(&from, 0, sizeof(from));
Kevin Steves678ee512003-01-01 23:43:55 +0000851 fromlen = sizeof(from);
Damien Miller942da032000-08-18 13:59:06 +1000852 if (packet_connection_is_on_socket()) {
Damien Miller942da032000-08-18 13:59:06 +1000853 if (getpeername(packet_get_connection_in(),
Darren Tucker43e7a352009-06-21 19:50:08 +1000854 (struct sockaddr *)&from, &fromlen) < 0) {
Damien Miller942da032000-08-18 13:59:06 +1000855 debug("getpeername: %.100s", strerror(errno));
Darren Tucker3e33cec2003-10-02 16:12:36 +1000856 cleanup_exit(255);
Damien Miller942da032000-08-18 13:59:06 +1000857 }
858 }
859
860 /* Record that there was a login on that tty from the remote host. */
Ben Lindstrom2bf56e22002-04-02 20:32:46 +0000861 if (!use_privsep)
862 record_login(pid, s->tty, pw->pw_name, pw->pw_uid,
863 get_remote_name_or_ip(utmp_len,
Damien Miller3a961dc2003-06-03 10:25:48 +1000864 options.use_dns),
Damien Millerebc23062002-09-04 16:45:09 +1000865 (struct sockaddr *)&from, fromlen);
Damien Miller942da032000-08-18 13:59:06 +1000866
Kevin Steves092f2ef2000-10-14 13:36:13 +0000867#ifdef USE_PAM
868 /*
869 * If password change is needed, do it now.
870 * This needs to occur before the ~/.hushlogin check.
871 */
Darren Tucker1921ed92004-02-10 13:23:28 +1100872 if (options.use_pam && !use_privsep && s->authctxt->force_pwchange) {
873 display_loginmsg();
Kevin Steves092f2ef2000-10-14 13:36:13 +0000874 do_pam_chauthtok();
Darren Tucker1921ed92004-02-10 13:23:28 +1100875 s->authctxt->force_pwchange = 0;
Damien Miller1f499fd2003-08-25 13:08:49 +1000876 /* XXX - signal [net] parent to enable forwardings */
Kevin Steves092f2ef2000-10-14 13:36:13 +0000877 }
878#endif
879
Damien Millercf205e82001-04-16 18:29:15 +1000880 if (check_quietlogin(s, command))
Damien Miller942da032000-08-18 13:59:06 +1000881 return;
882
Darren Tucker1921ed92004-02-10 13:23:28 +1100883 display_loginmsg();
Damien Miller942da032000-08-18 13:59:06 +1000884
Damien Millercf205e82001-04-16 18:29:15 +1000885 do_motd();
886}
887
888/*
889 * Display the message of the day.
890 */
891void
892do_motd(void)
893{
894 FILE *f;
895 char buf[256];
896
Damien Miller942da032000-08-18 13:59:06 +1000897 if (options.print_motd) {
Damien Millerad833b32000-08-23 10:46:23 +1000898#ifdef HAVE_LOGIN_CAP
899 f = fopen(login_getcapstr(lc, "welcome", "/etc/motd",
900 "/etc/motd"), "r");
901#else
Damien Miller942da032000-08-18 13:59:06 +1000902 f = fopen("/etc/motd", "r");
Damien Millerad833b32000-08-23 10:46:23 +1000903#endif
Damien Miller942da032000-08-18 13:59:06 +1000904 if (f) {
905 while (fgets(buf, sizeof(buf), f))
906 fputs(buf, stdout);
907 fclose(f);
908 }
909 }
910}
911
Kevin Steves8f63caa2001-07-04 18:23:02 +0000912
913/*
914 * Check for quiet login, either .hushlogin or command given.
915 */
916int
917check_quietlogin(Session *s, const char *command)
918{
919 char buf[256];
920 struct passwd *pw = s->pw;
921 struct stat st;
922
923 /* Return 1 if .hushlogin exists or a command given. */
924 if (command != NULL)
925 return 1;
926 snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir);
927#ifdef HAVE_LOGIN_CAP
928 if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0)
929 return 1;
930#else
931 if (stat(buf, &st) >= 0)
932 return 1;
933#endif
934 return 0;
935}
936
Damien Millerb38eff82000-04-01 11:09:21 +1000937/*
938 * Sets the value of the given variable in the environment. If the variable
Darren Tucker63917bd2008-11-11 16:33:48 +1100939 * already exists, its value is overridden.
Damien Millerb38eff82000-04-01 11:09:21 +1000940 */
Darren Tucker0efd1552003-08-26 11:49:55 +1000941void
Ben Lindstrom46c16222000-12-22 01:43:59 +0000942child_set_env(char ***envp, u_int *envsizep, const char *name,
Damien Miller9f0f5c62001-12-21 14:45:46 +1100943 const char *value)
Damien Millerb38eff82000-04-01 11:09:21 +1000944{
Damien Millerb38eff82000-04-01 11:09:21 +1000945 char **env;
Darren Tuckerfb16b242003-09-22 21:04:23 +1000946 u_int envsize;
947 u_int i, namelen;
Damien Millerb38eff82000-04-01 11:09:21 +1000948
949 /*
Darren Tuckere1a790d2003-09-16 11:52:19 +1000950 * If we're passed an uninitialized list, allocate a single null
951 * entry before continuing.
952 */
953 if (*envp == NULL && *envsizep == 0) {
954 *envp = xmalloc(sizeof(char *));
955 *envp[0] = NULL;
956 *envsizep = 1;
957 }
958
959 /*
Damien Millerb38eff82000-04-01 11:09:21 +1000960 * Find the slot where the value should be stored. If the variable
961 * already exists, we reuse the slot; otherwise we append a new slot
962 * at the end of the array, expanding if necessary.
963 */
964 env = *envp;
965 namelen = strlen(name);
966 for (i = 0; env[i]; i++)
967 if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
968 break;
969 if (env[i]) {
970 /* Reuse the slot. */
971 xfree(env[i]);
972 } else {
973 /* New variable. Expand if necessary. */
Darren Tuckerfb16b242003-09-22 21:04:23 +1000974 envsize = *envsizep;
975 if (i >= envsize - 1) {
976 if (envsize >= 1000)
977 fatal("child_set_env: too many env vars");
978 envsize += 50;
Damien Miller36812092006-03-26 14:22:47 +1100979 env = (*envp) = xrealloc(env, envsize, sizeof(char *));
Darren Tuckerfb16b242003-09-22 21:04:23 +1000980 *envsizep = envsize;
Damien Millerb38eff82000-04-01 11:09:21 +1000981 }
982 /* Need to set the NULL pointer at end of array beyond the new slot. */
983 env[i + 1] = NULL;
984 }
985
986 /* Allocate space and format the variable in the appropriate slot. */
987 env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
988 snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
989}
990
991/*
992 * Reads environment variables from the given file and adds/overrides them
993 * into the environment. If the file does not exist, this does nothing.
994 * Otherwise, it must consist of empty lines, comments (line starts with '#')
995 * and assignments of the form name=value. No other forms are allowed.
996 */
Ben Lindstrombba81212001-06-25 05:01:22 +0000997static void
Ben Lindstrom46c16222000-12-22 01:43:59 +0000998read_environment_file(char ***env, u_int *envsize,
Damien Miller9f0f5c62001-12-21 14:45:46 +1100999 const char *filename)
Damien Millerb38eff82000-04-01 11:09:21 +10001000{
1001 FILE *f;
1002 char buf[4096];
1003 char *cp, *value;
Damien Miller990070a2002-06-26 23:51:06 +10001004 u_int lineno = 0;
Damien Millerb38eff82000-04-01 11:09:21 +10001005
1006 f = fopen(filename, "r");
1007 if (!f)
1008 return;
1009
1010 while (fgets(buf, sizeof(buf), f)) {
Damien Miller990070a2002-06-26 23:51:06 +10001011 if (++lineno > 1000)
1012 fatal("Too many lines in environment file %s", filename);
Damien Millerb38eff82000-04-01 11:09:21 +10001013 for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
1014 ;
1015 if (!*cp || *cp == '#' || *cp == '\n')
1016 continue;
Damien Miller14b017d2007-09-17 16:09:15 +10001017
1018 cp[strcspn(cp, "\n")] = '\0';
1019
Damien Millerb38eff82000-04-01 11:09:21 +10001020 value = strchr(cp, '=');
1021 if (value == NULL) {
Damien Miller990070a2002-06-26 23:51:06 +10001022 fprintf(stderr, "Bad line %u in %.100s\n", lineno,
1023 filename);
Damien Millerb38eff82000-04-01 11:09:21 +10001024 continue;
1025 }
Damien Millerb1715dc2000-05-30 13:44:51 +10001026 /*
1027 * Replace the equals sign by nul, and advance value to
1028 * the value string.
1029 */
Damien Millerb38eff82000-04-01 11:09:21 +10001030 *value = '\0';
1031 value++;
1032 child_set_env(env, envsize, cp, value);
1033 }
1034 fclose(f);
1035}
1036
Darren Tuckere1a790d2003-09-16 11:52:19 +10001037#ifdef HAVE_ETC_DEFAULT_LOGIN
1038/*
1039 * Return named variable from specified environment, or NULL if not present.
1040 */
1041static char *
1042child_get_env(char **env, const char *name)
1043{
1044 int i;
1045 size_t len;
1046
1047 len = strlen(name);
1048 for (i=0; env[i] != NULL; i++)
1049 if (strncmp(name, env[i], len) == 0 && env[i][len] == '=')
1050 return(env[i] + len + 1);
1051 return NULL;
1052}
1053
1054/*
1055 * Read /etc/default/login.
1056 * We pick up the PATH (or SUPATH for root) and UMASK.
1057 */
1058static void
1059read_etc_default_login(char ***env, u_int *envsize, uid_t uid)
1060{
1061 char **tmpenv = NULL, *var;
Darren Tuckerc11b1e82003-09-19 20:56:51 +10001062 u_int i, tmpenvsize = 0;
Darren Tuckerf391ba62003-10-02 20:07:09 +10001063 u_long mask;
Darren Tuckere1a790d2003-09-16 11:52:19 +10001064
1065 /*
1066 * We don't want to copy the whole file to the child's environment,
1067 * so we use a temporary environment and copy the variables we're
1068 * interested in.
1069 */
1070 read_environment_file(&tmpenv, &tmpenvsize, "/etc/default/login");
1071
Darren Tuckerc11b1e82003-09-19 20:56:51 +10001072 if (tmpenv == NULL)
1073 return;
1074
Darren Tuckere1a790d2003-09-16 11:52:19 +10001075 if (uid == 0)
1076 var = child_get_env(tmpenv, "SUPATH");
1077 else
1078 var = child_get_env(tmpenv, "PATH");
1079 if (var != NULL)
1080 child_set_env(env, envsize, "PATH", var);
Damien Miller787b2ec2003-11-21 23:56:47 +11001081
Darren Tuckere1a790d2003-09-16 11:52:19 +10001082 if ((var = child_get_env(tmpenv, "UMASK")) != NULL)
1083 if (sscanf(var, "%5lo", &mask) == 1)
Darren Tuckerf391ba62003-10-02 20:07:09 +10001084 umask((mode_t)mask);
Damien Miller787b2ec2003-11-21 23:56:47 +11001085
Darren Tuckere1a790d2003-09-16 11:52:19 +10001086 for (i = 0; tmpenv[i] != NULL; i++)
1087 xfree(tmpenv[i]);
1088 xfree(tmpenv);
1089}
1090#endif /* HAVE_ETC_DEFAULT_LOGIN */
1091
Damien Miller7dff8692005-05-26 11:34:51 +10001092void
1093copy_environment(char **source, char ***env, u_int *envsize)
Damien Millerb38eff82000-04-01 11:09:21 +10001094{
Damien Millerbb9ffc12002-01-08 10:59:32 +11001095 char *var_name, *var_val;
Damien Millerb38eff82000-04-01 11:09:21 +10001096 int i;
1097
Damien Millerbb9ffc12002-01-08 10:59:32 +11001098 if (source == NULL)
Damien Millerb38eff82000-04-01 11:09:21 +10001099 return;
Kevin Stevesef4eea92001-02-05 12:42:17 +00001100
Damien Millerbb9ffc12002-01-08 10:59:32 +11001101 for(i = 0; source[i] != NULL; i++) {
1102 var_name = xstrdup(source[i]);
1103 if ((var_val = strstr(var_name, "=")) == NULL) {
1104 xfree(var_name);
Damien Millerb38eff82000-04-01 11:09:21 +10001105 continue;
Damien Millerb38eff82000-04-01 11:09:21 +10001106 }
Damien Millerbb9ffc12002-01-08 10:59:32 +11001107 *var_val++ = '\0';
1108
1109 debug3("Copy environment: %s=%s", var_name, var_val);
1110 child_set_env(env, envsize, var_name, var_val);
Damien Miller787b2ec2003-11-21 23:56:47 +11001111
Damien Millerbb9ffc12002-01-08 10:59:32 +11001112 xfree(var_name);
Damien Millerb38eff82000-04-01 11:09:21 +10001113 }
1114}
Damien Millercb5e44a2000-09-29 12:12:36 +11001115
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001116static char **
1117do_setup_env(Session *s, const char *shell)
Damien Millerb38eff82000-04-01 11:09:21 +10001118{
Damien Millerb38eff82000-04-01 11:09:21 +10001119 char buf[256];
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001120 u_int i, envsize;
Damien Millerad5ecbf2006-07-24 15:03:06 +10001121 char **env, *laddr;
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001122 struct passwd *pw = s->pw;
Darren Tucker9d86e5d2009-03-08 11:40:27 +11001123#if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN)
Damien Millerad5ecbf2006-07-24 15:03:06 +10001124 char *path = NULL;
1125#endif
Damien Millerb38eff82000-04-01 11:09:21 +10001126
Damien Millerb38eff82000-04-01 11:09:21 +10001127 /* Initialize the environment. */
1128 envsize = 100;
Darren Tuckerd8093e42006-05-04 16:24:34 +10001129 env = xcalloc(envsize, sizeof(char *));
Damien Millerb38eff82000-04-01 11:09:21 +10001130 env[0] = NULL;
1131
Damien Millerbac2d8a2000-09-05 16:13:06 +11001132#ifdef HAVE_CYGWIN
1133 /*
1134 * The Windows environment contains some setting which are
1135 * important for a running system. They must not be dropped.
1136 */
Darren Tucker14c372d2004-08-30 20:42:08 +10001137 {
1138 char **p;
1139
1140 p = fetch_windows_environment();
1141 copy_environment(p, &env, &envsize);
1142 free_windows_environment(p);
1143 }
Damien Millerbac2d8a2000-09-05 16:13:06 +11001144#endif
1145
Darren Tucker0efd1552003-08-26 11:49:55 +10001146#ifdef GSSAPI
Damien Millera8e06ce2003-11-21 23:48:55 +11001147 /* Allow any GSSAPI methods that we've used to alter
Darren Tucker0efd1552003-08-26 11:49:55 +10001148 * the childs environment as they see fit
1149 */
1150 ssh_gssapi_do_child(&env, &envsize);
1151#endif
1152
Damien Millerb38eff82000-04-01 11:09:21 +10001153 if (!options.use_login) {
1154 /* Set basic environment. */
Darren Tucker46bc0752004-05-02 22:11:30 +10001155 for (i = 0; i < s->num_env; i++)
Darren Tuckerfc959702004-07-17 16:12:08 +10001156 child_set_env(&env, &envsize, s->env[i].name,
Darren Tucker46bc0752004-05-02 22:11:30 +10001157 s->env[i].val);
1158
Damien Millerb38eff82000-04-01 11:09:21 +10001159 child_set_env(&env, &envsize, "USER", pw->pw_name);
1160 child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
Damien Millerdfedbf82003-01-03 14:52:53 +11001161#ifdef _AIX
1162 child_set_env(&env, &envsize, "LOGIN", pw->pw_name);
1163#endif
Damien Millerb38eff82000-04-01 11:09:21 +10001164 child_set_env(&env, &envsize, "HOME", pw->pw_dir);
Damien Millerad833b32000-08-23 10:46:23 +10001165#ifdef HAVE_LOGIN_CAP
Ben Lindstromb9051ec2002-07-23 21:11:09 +00001166 if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETPATH) < 0)
1167 child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
1168 else
1169 child_set_env(&env, &envsize, "PATH", getenv("PATH"));
Damien Millercb5e44a2000-09-29 12:12:36 +11001170#else /* HAVE_LOGIN_CAP */
1171# ifndef HAVE_CYGWIN
Damien Millerbac2d8a2000-09-05 16:13:06 +11001172 /*
1173 * There's no standard path on Windows. The path contains
1174 * important components pointing to the system directories,
1175 * needed for loading shared libraries. So the path better
1176 * remains intact here.
1177 */
Darren Tuckere1a790d2003-09-16 11:52:19 +10001178# ifdef HAVE_ETC_DEFAULT_LOGIN
1179 read_etc_default_login(&env, &envsize, pw->pw_uid);
1180 path = child_get_env(env, "PATH");
1181# endif /* HAVE_ETC_DEFAULT_LOGIN */
1182 if (path == NULL || *path == '\0') {
Damien Millera8e06ce2003-11-21 23:48:55 +11001183 child_set_env(&env, &envsize, "PATH",
Darren Tuckere1a790d2003-09-16 11:52:19 +10001184 s->pw->pw_uid == 0 ?
1185 SUPERUSER_PATH : _PATH_STDPATH);
1186 }
Damien Millercb5e44a2000-09-29 12:12:36 +11001187# endif /* HAVE_CYGWIN */
1188#endif /* HAVE_LOGIN_CAP */
Damien Millerb38eff82000-04-01 11:09:21 +10001189
1190 snprintf(buf, sizeof buf, "%.200s/%.50s",
1191 _PATH_MAILDIR, pw->pw_name);
1192 child_set_env(&env, &envsize, "MAIL", buf);
1193
1194 /* Normal systems set SHELL by default. */
1195 child_set_env(&env, &envsize, "SHELL", shell);
1196 }
1197 if (getenv("TZ"))
1198 child_set_env(&env, &envsize, "TZ", getenv("TZ"));
1199
1200 /* Set custom environment options from RSA authentication. */
Ben Lindstrom38b951c2001-12-06 17:47:47 +00001201 if (!options.use_login) {
1202 while (custom_environment) {
1203 struct envstring *ce = custom_environment;
Ben Lindstrom5a9d0ea2002-07-04 00:12:53 +00001204 char *str = ce->s;
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001205
Ben Lindstrom5a9d0ea2002-07-04 00:12:53 +00001206 for (i = 0; str[i] != '=' && str[i]; i++)
Ben Lindstrom38b951c2001-12-06 17:47:47 +00001207 ;
Ben Lindstrom5a9d0ea2002-07-04 00:12:53 +00001208 if (str[i] == '=') {
1209 str[i] = 0;
1210 child_set_env(&env, &envsize, str, str + i + 1);
Ben Lindstrom38b951c2001-12-06 17:47:47 +00001211 }
1212 custom_environment = ce->next;
1213 xfree(ce->s);
1214 xfree(ce);
Damien Millerb38eff82000-04-01 11:09:21 +10001215 }
Damien Millerb38eff82000-04-01 11:09:21 +10001216 }
1217
Damien Millerf37e2462002-09-19 11:47:55 +10001218 /* SSH_CLIENT deprecated */
Damien Millerb38eff82000-04-01 11:09:21 +10001219 snprintf(buf, sizeof buf, "%.50s %d %d",
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001220 get_remote_ipaddr(), get_remote_port(), get_local_port());
Damien Millerb38eff82000-04-01 11:09:21 +10001221 child_set_env(&env, &envsize, "SSH_CLIENT", buf);
1222
Damien Miller00111382003-03-10 11:21:17 +11001223 laddr = get_local_ipaddr(packet_get_connection_in());
Damien Millerf37e2462002-09-19 11:47:55 +10001224 snprintf(buf, sizeof buf, "%.50s %d %.50s %d",
Damien Miller00111382003-03-10 11:21:17 +11001225 get_remote_ipaddr(), get_remote_port(), laddr, get_local_port());
1226 xfree(laddr);
Damien Millerf37e2462002-09-19 11:47:55 +10001227 child_set_env(&env, &envsize, "SSH_CONNECTION", buf);
1228
Ben Lindstrom86fe8682001-03-17 00:32:57 +00001229 if (s->ttyfd != -1)
1230 child_set_env(&env, &envsize, "SSH_TTY", s->tty);
1231 if (s->term)
1232 child_set_env(&env, &envsize, "TERM", s->term);
1233 if (s->display)
1234 child_set_env(&env, &envsize, "DISPLAY", s->display);
Damien Miller7b28dc52000-09-05 13:34:53 +11001235 if (original_command)
1236 child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND",
1237 original_command);
Damien Millerb38eff82000-04-01 11:09:21 +10001238
Tim Rice81ed5182002-09-25 17:38:46 -07001239#ifdef _UNICOS
1240 if (cray_tmpdir[0] != '\0')
1241 child_set_env(&env, &envsize, "TMPDIR", cray_tmpdir);
1242#endif /* _UNICOS */
1243
Darren Tucker9dc6c7d2005-02-02 18:30:33 +11001244 /*
1245 * Since we clear KRB5CCNAME at startup, if it's set now then it
1246 * must have been set by a native authentication method (eg AIX or
1247 * SIA), so copy it to the child.
1248 */
1249 {
1250 char *cp;
1251
1252 if ((cp = getenv("KRB5CCNAME")) != NULL)
1253 child_set_env(&env, &envsize, "KRB5CCNAME", cp);
1254 }
1255
Damien Millerb38eff82000-04-01 11:09:21 +10001256#ifdef _AIX
Ben Lindstrom839ac4f2002-02-24 20:42:46 +00001257 {
1258 char *cp;
1259
1260 if ((cp = getenv("AUTHSTATE")) != NULL)
1261 child_set_env(&env, &envsize, "AUTHSTATE", cp);
Ben Lindstrom839ac4f2002-02-24 20:42:46 +00001262 read_environment_file(&env, &envsize, "/etc/environment");
1263 }
Damien Millerb38eff82000-04-01 11:09:21 +10001264#endif
Ben Lindstromec95ed92001-07-04 04:21:14 +00001265#ifdef KRB5
Damien Miller9c870f92004-04-16 22:47:55 +10001266 if (s->authctxt->krb5_ccname)
Ben Lindstromec95ed92001-07-04 04:21:14 +00001267 child_set_env(&env, &envsize, "KRB5CCNAME",
Damien Miller9c870f92004-04-16 22:47:55 +10001268 s->authctxt->krb5_ccname);
Ben Lindstromec95ed92001-07-04 04:21:14 +00001269#endif
Damien Millerb38eff82000-04-01 11:09:21 +10001270#ifdef USE_PAM
Kevin Steves38b050a2002-07-23 00:44:07 +00001271 /*
1272 * Pull in any environment variables that may have
1273 * been set by PAM.
1274 */
Damien Miller4e448a32003-05-14 15:11:48 +10001275 if (options.use_pam) {
Damien Millerc756e9b2003-11-17 21:41:42 +11001276 char **p;
Damien Miller787b2ec2003-11-21 23:56:47 +11001277
Damien Millerc756e9b2003-11-17 21:41:42 +11001278 p = fetch_pam_child_environment();
1279 copy_environment(p, &env, &envsize);
1280 free_pam_environment(p);
Kevin Steves38b050a2002-07-23 00:44:07 +00001281
Damien Millerc756e9b2003-11-17 21:41:42 +11001282 p = fetch_pam_environment();
Kevin Steves38b050a2002-07-23 00:44:07 +00001283 copy_environment(p, &env, &envsize);
1284 free_pam_environment(p);
1285 }
Damien Millerb38eff82000-04-01 11:09:21 +10001286#endif /* USE_PAM */
1287
Ben Lindstrom8bb6f362002-06-11 15:59:02 +00001288 if (auth_sock_name != NULL)
Damien Millerb38eff82000-04-01 11:09:21 +10001289 child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
Ben Lindstrom8bb6f362002-06-11 15:59:02 +00001290 auth_sock_name);
Damien Millerb38eff82000-04-01 11:09:21 +10001291
1292 /* read $HOME/.ssh/environment. */
Ben Lindstrom5d860f02002-08-01 01:28:38 +00001293 if (options.permit_user_env && !options.use_login) {
Damien Millerb1715dc2000-05-30 13:44:51 +10001294 snprintf(buf, sizeof buf, "%.200s/.ssh/environment",
Damien Millere9994cb2002-09-10 21:43:53 +10001295 strcmp(pw->pw_dir, "/") ? pw->pw_dir : "");
Damien Millerb38eff82000-04-01 11:09:21 +10001296 read_environment_file(&env, &envsize, buf);
1297 }
1298 if (debug_flag) {
1299 /* dump the environment */
1300 fprintf(stderr, "Environment:\n");
1301 for (i = 0; env[i]; i++)
1302 fprintf(stderr, " %.200s\n", env[i]);
1303 }
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001304 return env;
1305}
1306
1307/*
1308 * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found
1309 * first in this order).
1310 */
1311static void
1312do_rc_files(Session *s, const char *shell)
1313{
1314 FILE *f = NULL;
1315 char cmd[1024];
1316 int do_xauth;
1317 struct stat st;
1318
1319 do_xauth =
1320 s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL;
1321
Damien Millera1b48cc2008-03-27 11:02:02 +11001322 /* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */
Damien Miller55360e12008-03-27 11:02:27 +11001323 if (!s->is_subsystem && options.adm_forced_command == NULL &&
Damien Millerff0dd882008-05-19 14:55:02 +10001324 !no_user_rc && stat(_PATH_SSH_USER_RC, &st) >= 0) {
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001325 snprintf(cmd, sizeof cmd, "%s -c '%s %s'",
1326 shell, _PATH_BSHELL, _PATH_SSH_USER_RC);
1327 if (debug_flag)
1328 fprintf(stderr, "Running %s\n", cmd);
1329 f = popen(cmd, "w");
1330 if (f) {
1331 if (do_xauth)
1332 fprintf(f, "%s %s\n", s->auth_proto,
1333 s->auth_data);
1334 pclose(f);
1335 } else
1336 fprintf(stderr, "Could not run %s\n",
1337 _PATH_SSH_USER_RC);
1338 } else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) {
1339 if (debug_flag)
1340 fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,
1341 _PATH_SSH_SYSTEM_RC);
1342 f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w");
1343 if (f) {
1344 if (do_xauth)
1345 fprintf(f, "%s %s\n", s->auth_proto,
1346 s->auth_data);
1347 pclose(f);
1348 } else
1349 fprintf(stderr, "Could not run %s\n",
1350 _PATH_SSH_SYSTEM_RC);
1351 } else if (do_xauth && options.xauth_location != NULL) {
1352 /* Add authority data to .Xauthority if appropriate. */
1353 if (debug_flag) {
1354 fprintf(stderr,
Ben Lindstrom611797e2002-12-23 02:15:57 +00001355 "Running %.500s remove %.100s\n",
Darren Tucker3e33cec2003-10-02 16:12:36 +10001356 options.xauth_location, s->auth_display);
Ben Lindstrom611797e2002-12-23 02:15:57 +00001357 fprintf(stderr,
1358 "%.500s add %.100s %.100s %.100s\n",
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001359 options.xauth_location, s->auth_display,
1360 s->auth_proto, s->auth_data);
1361 }
1362 snprintf(cmd, sizeof cmd, "%s -q -",
1363 options.xauth_location);
1364 f = popen(cmd, "w");
1365 if (f) {
Ben Lindstrom611797e2002-12-23 02:15:57 +00001366 fprintf(f, "remove %s\n",
1367 s->auth_display);
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001368 fprintf(f, "add %s %s %s\n",
1369 s->auth_display, s->auth_proto,
1370 s->auth_data);
1371 pclose(f);
1372 } else {
1373 fprintf(stderr, "Could not run %s\n",
1374 cmd);
1375 }
1376 }
1377}
1378
1379static void
1380do_nologin(struct passwd *pw)
1381{
1382 FILE *f = NULL;
Darren Tucker09aa4c02010-01-12 19:51:48 +11001383 char buf[1024], *nl, *def_nl = _PATH_NOLOGIN;
1384 struct stat sb;
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001385
1386#ifdef HAVE_LOGIN_CAP
Darren Tucker09aa4c02010-01-12 19:51:48 +11001387 if (login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid)
1388 return;
1389 nl = login_getcapstr(lc, "nologin", def_nl, def_nl);
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001390#else
Darren Tucker09aa4c02010-01-12 19:51:48 +11001391 if (pw->pw_uid == 0)
1392 return;
1393 nl = def_nl;
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001394#endif
Darren Tucker09aa4c02010-01-12 19:51:48 +11001395 if (stat(nl, &sb) == -1) {
1396 if (nl != def_nl)
1397 xfree(nl);
1398 return;
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001399 }
Darren Tucker09aa4c02010-01-12 19:51:48 +11001400
1401 /* /etc/nologin exists. Print its contents if we can and exit. */
1402 logit("User %.100s not allowed because %s exists", pw->pw_name, nl);
1403 if ((f = fopen(nl, "r")) != NULL) {
1404 while (fgets(buf, sizeof(buf), f))
1405 fputs(buf, stderr);
1406 fclose(f);
1407 }
1408 exit(254);
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001409}
1410
Damien Millerd8cb1f12008-02-10 22:40:12 +11001411/*
1412 * Chroot into a directory after checking it for safety: all path components
1413 * must be root-owned directories with strict permissions.
1414 */
1415static void
1416safely_chroot(const char *path, uid_t uid)
1417{
1418 const char *cp;
1419 char component[MAXPATHLEN];
1420 struct stat st;
1421
1422 if (*path != '/')
1423 fatal("chroot path does not begin at root");
1424 if (strlen(path) >= sizeof(component))
1425 fatal("chroot path too long");
1426
1427 /*
1428 * Descend the path, checking that each component is a
1429 * root-owned directory with strict permissions.
1430 */
1431 for (cp = path; cp != NULL;) {
1432 if ((cp = strchr(cp, '/')) == NULL)
1433 strlcpy(component, path, sizeof(component));
1434 else {
1435 cp++;
1436 memcpy(component, path, cp - path);
1437 component[cp - path] = '\0';
1438 }
1439
1440 debug3("%s: checking '%s'", __func__, component);
1441
1442 if (stat(component, &st) != 0)
1443 fatal("%s: stat(\"%s\"): %s", __func__,
1444 component, strerror(errno));
1445 if (st.st_uid != 0 || (st.st_mode & 022) != 0)
1446 fatal("bad ownership or modes for chroot "
1447 "directory %s\"%s\"",
1448 cp == NULL ? "" : "component ", component);
1449 if (!S_ISDIR(st.st_mode))
1450 fatal("chroot path %s\"%s\" is not a directory",
1451 cp == NULL ? "" : "component ", component);
1452
1453 }
1454
1455 if (chdir(path) == -1)
1456 fatal("Unable to chdir to chroot path \"%s\": "
1457 "%s", path, strerror(errno));
1458 if (chroot(path) == -1)
1459 fatal("chroot(\"%s\"): %s", path, strerror(errno));
1460 if (chdir("/") == -1)
1461 fatal("%s: chdir(/) after chroot: %s",
1462 __func__, strerror(errno));
1463 verbose("Changed root directory to \"%s\"", path);
1464}
1465
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001466/* Set login name, uid, gid, and groups. */
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00001467void
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001468do_setusercontext(struct passwd *pw)
1469{
Damien Miller54e37732008-02-10 22:48:55 +11001470 char *chroot_path, *tmp;
1471
Darren Tuckerb8eb5862008-03-27 07:27:20 +11001472#ifdef WITH_SELINUX
1473 /* Cache selinux status for later use */
1474 (void)ssh_selinux_enabled();
1475#endif
1476
Damien Miller1a3ccb02003-02-24 13:04:01 +11001477#ifndef HAVE_CYGWIN
1478 if (getuid() == 0 || geteuid() == 0)
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001479#endif /* HAVE_CYGWIN */
Damien Miller1a3ccb02003-02-24 13:04:01 +11001480 {
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001481#ifdef HAVE_LOGIN_CAP
Ben Lindstrom938b8282002-07-15 17:58:34 +00001482# ifdef __bsdi__
Damien Millerf18cd162002-06-26 19:12:59 +10001483 setpgid(0, 0);
Ben Lindstrom938b8282002-07-15 17:58:34 +00001484# endif
Damien Millerd3526362004-01-23 14:16:26 +11001485# ifdef USE_PAM
1486 if (options.use_pam) {
Darren Tucker2d963642007-08-13 23:11:56 +10001487 do_pam_setcred(use_privsep);
Damien Millerd3526362004-01-23 14:16:26 +11001488 }
1489# endif /* USE_PAM */
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001490 if (setusercontext(lc, pw, pw->pw_uid,
Damien Millerd8cb1f12008-02-10 22:40:12 +11001491 (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETUSER))) < 0) {
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001492 perror("unable to set user context");
1493 exit(1);
1494 }
1495#else
1496# if defined(HAVE_GETLUID) && defined(HAVE_SETLUID)
1497 /* Sets login uid for accounting */
1498 if (getluid() == -1 && setluid(pw->pw_uid) == -1)
1499 error("setluid: %s", strerror(errno));
1500# endif /* defined(HAVE_GETLUID) && defined(HAVE_SETLUID) */
1501
1502 if (setlogin(pw->pw_name) < 0)
1503 error("setlogin failed: %s", strerror(errno));
1504 if (setgid(pw->pw_gid) < 0) {
1505 perror("setgid");
1506 exit(1);
1507 }
1508 /* Initialize the group list. */
1509 if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
1510 perror("initgroups");
1511 exit(1);
1512 }
1513 endgrent();
1514# ifdef USE_PAM
1515 /*
Damien Millera8e06ce2003-11-21 23:48:55 +11001516 * PAM credentials may take the form of supplementary groups.
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001517 * These will have been wiped by the above initgroups() call.
1518 * Reestablish them here.
1519 */
Damien Miller341c6e62003-09-02 23:18:52 +10001520 if (options.use_pam) {
Darren Tucker2d963642007-08-13 23:11:56 +10001521 do_pam_setcred(use_privsep);
Damien Miller341c6e62003-09-02 23:18:52 +10001522 }
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001523# endif /* USE_PAM */
1524# if defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY)
1525 irix_setusercontext(pw);
Damien Millerd8cb1f12008-02-10 22:40:12 +11001526# endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */
Ben Lindstromb129be62002-06-25 17:12:26 +00001527# ifdef _AIX
Ben Lindstrom51b24882002-07-04 03:08:40 +00001528 aix_usrinfo(pw);
Ben Lindstromb129be62002-06-25 17:12:26 +00001529# endif /* _AIX */
Damien Millerd8cb1f12008-02-10 22:40:12 +11001530# ifdef USE_LIBIAF
Tim Rice2291c002005-08-26 13:15:19 -07001531 if (set_id(pw->pw_name) != 0) {
1532 exit(1);
1533 }
Damien Millerd8cb1f12008-02-10 22:40:12 +11001534# endif /* USE_LIBIAF */
1535#endif
Darren Tuckerc738e6c2010-03-07 13:21:12 +11001536#ifdef HAVE_SETPCRED
1537 /*
1538 * If we have a chroot directory, we set all creds except real
1539 * uid which we will need for chroot. If we don't have a
1540 * chroot directory, we don't override anything.
1541 */
1542 {
Darren Tuckerac0c4c92010-03-07 13:32:16 +11001543 char **creds = NULL, *chroot_creds[] =
Darren Tuckerc738e6c2010-03-07 13:21:12 +11001544 { "REAL_USER=root", NULL };
1545
1546 if (options.chroot_directory != NULL &&
1547 strcasecmp(options.chroot_directory, "none") != 0)
1548 creds = chroot_creds;
1549
1550 if (setpcred(pw->pw_name, creds) == -1)
1551 fatal("Failed to set process credentials");
1552 }
1553#endif /* HAVE_SETPCRED */
Damien Millerd8cb1f12008-02-10 22:40:12 +11001554
Damien Miller8b906422010-03-26 11:04:09 +11001555#ifdef WITH_SELINUX
1556 ssh_selinux_setup_exec_context(pw->pw_name);
1557#endif
1558
Damien Millerd8cb1f12008-02-10 22:40:12 +11001559 if (options.chroot_directory != NULL &&
1560 strcasecmp(options.chroot_directory, "none") != 0) {
Damien Miller54e37732008-02-10 22:48:55 +11001561 tmp = tilde_expand_filename(options.chroot_directory,
1562 pw->pw_uid);
1563 chroot_path = percent_expand(tmp, "h", pw->pw_dir,
1564 "u", pw->pw_name, (char *)NULL);
Damien Millerd8cb1f12008-02-10 22:40:12 +11001565 safely_chroot(chroot_path, pw->pw_uid);
Damien Miller54e37732008-02-10 22:48:55 +11001566 free(tmp);
Damien Millerd8cb1f12008-02-10 22:40:12 +11001567 free(chroot_path);
1568 }
1569
1570#ifdef HAVE_LOGIN_CAP
1571 if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUSER) < 0) {
1572 perror("unable to set user context (setuser)");
1573 exit(1);
1574 }
1575#else
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001576 /* Permanently switch to the desired uid. */
1577 permanently_set_uid(pw);
1578#endif
1579 }
Damien Miller1a3ccb02003-02-24 13:04:01 +11001580
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001581 if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
1582 fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
1583}
1584
Ben Lindstrom08105192002-03-22 02:50:06 +00001585static void
Darren Tucker23bc8d02004-02-06 16:24:31 +11001586do_pwchange(Session *s)
1587{
Darren Tucker09991742004-07-17 17:05:14 +10001588 fflush(NULL);
Darren Tucker23bc8d02004-02-06 16:24:31 +11001589 fprintf(stderr, "WARNING: Your password has expired.\n");
1590 if (s->ttyfd != -1) {
Darren Tuckerfc959702004-07-17 16:12:08 +10001591 fprintf(stderr,
Darren Tucker23bc8d02004-02-06 16:24:31 +11001592 "You must change your password now and login again!\n");
Darren Tucker33370e02005-02-09 22:17:28 +11001593#ifdef PASSWD_NEEDS_USERNAME
1594 execl(_PATH_PASSWD_PROG, "passwd", s->pw->pw_name,
1595 (char *)NULL);
1596#else
Darren Tucker23bc8d02004-02-06 16:24:31 +11001597 execl(_PATH_PASSWD_PROG, "passwd", (char *)NULL);
Darren Tucker33370e02005-02-09 22:17:28 +11001598#endif
Darren Tucker23bc8d02004-02-06 16:24:31 +11001599 perror("passwd");
1600 } else {
1601 fprintf(stderr,
1602 "Password change required but no TTY available.\n");
1603 }
1604 exit(1);
1605}
1606
1607static void
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00001608launch_login(struct passwd *pw, const char *hostname)
1609{
1610 /* Launch login(1). */
1611
Ben Lindstrom378a4172002-06-07 14:49:56 +00001612 execl(LOGIN_PROGRAM, "login", "-h", hostname,
Kevin Stevesb4799a32002-03-24 23:19:54 +00001613#ifdef xxxLOGIN_NEEDS_TERM
Ben Lindstrom5a6abda2002-06-09 19:41:48 +00001614 (s->term ? s->term : "unknown"),
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00001615#endif /* LOGIN_NEEDS_TERM */
Kevin Steves5feaaef2002-04-23 20:45:55 +00001616#ifdef LOGIN_NO_ENDOPT
1617 "-p", "-f", pw->pw_name, (char *)NULL);
1618#else
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00001619 "-p", "-f", "--", pw->pw_name, (char *)NULL);
Kevin Steves5feaaef2002-04-23 20:45:55 +00001620#endif
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00001621
1622 /* Login couldn't be executed, die. */
1623
1624 perror("login");
1625 exit(1);
1626}
1627
Darren Tucker23bc8d02004-02-06 16:24:31 +11001628static void
1629child_close_fds(void)
1630{
1631 int i;
1632
1633 if (packet_get_connection_in() == packet_get_connection_out())
1634 close(packet_get_connection_in());
1635 else {
1636 close(packet_get_connection_in());
1637 close(packet_get_connection_out());
1638 }
1639 /*
1640 * Close all descriptors related to channels. They will still remain
1641 * open in the parent.
1642 */
1643 /* XXX better use close-on-exec? -markus */
1644 channel_close_all();
1645
1646 /*
1647 * Close any extra file descriptors. Note that there may still be
1648 * descriptors left by system functions. They will be closed later.
1649 */
1650 endpwent();
1651
1652 /*
Damien Miller788f2122005-11-05 15:14:59 +11001653 * Close any extra open file descriptors so that we don't have them
Darren Tucker23bc8d02004-02-06 16:24:31 +11001654 * hanging around in clients. Note that we want to do this after
1655 * initgroups, because at least on Solaris 2.3 it leaves file
1656 * descriptors open.
1657 */
1658 for (i = 3; i < 64; i++)
1659 close(i);
1660}
1661
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001662/*
1663 * Performs common processing for the child, such as setting up the
1664 * environment, closing extra file descriptors, setting the user and group
1665 * ids, and executing the command or shell.
1666 */
Damien Millerdfc24252008-02-10 22:29:40 +11001667#define ARGV_MAX 10
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001668void
1669do_child(Session *s, const char *command)
1670{
1671 extern char **environ;
1672 char **env;
Damien Millerdfc24252008-02-10 22:29:40 +11001673 char *argv[ARGV_MAX];
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001674 const char *shell, *shell0, *hostname = NULL;
1675 struct passwd *pw = s->pw;
Damien Miller6051c942008-06-16 07:53:16 +10001676 int r = 0;
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001677
1678 /* remove hostkey from the child's memory */
1679 destroy_sensitive_data();
1680
Darren Tucker23bc8d02004-02-06 16:24:31 +11001681 /* Force a password change */
1682 if (s->authctxt->force_pwchange) {
1683 do_setusercontext(pw);
1684 child_close_fds();
1685 do_pwchange(s);
1686 exit(1);
1687 }
1688
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001689 /* login(1) is only called if we execute the login shell */
1690 if (options.use_login && command != NULL)
1691 options.use_login = 0;
1692
Tim Rice81ed5182002-09-25 17:38:46 -07001693#ifdef _UNICOS
1694 cray_setup(pw->pw_uid, pw->pw_name, command);
1695#endif /* _UNICOS */
1696
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001697 /*
1698 * Login(1) does this as well, and it needs uid 0 for the "-h"
1699 * switch, so we let login(1) to this for us.
1700 */
1701 if (!options.use_login) {
1702#ifdef HAVE_OSF_SIA
Ben Lindstromc8c548d2003-03-21 01:18:09 +00001703 session_setup_sia(pw, s->ttyfd == -1 ? NULL : s->tty);
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001704 if (!check_quietlogin(s, command))
1705 do_motd();
1706#else /* HAVE_OSF_SIA */
Darren Tucker42308a42005-10-30 15:31:55 +11001707 /* When PAM is enabled we rely on it to do the nologin check */
1708 if (!options.use_pam)
1709 do_nologin(pw);
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001710 do_setusercontext(pw);
Darren Tucker0a44d1e2004-07-01 09:48:29 +10001711 /*
1712 * PAM session modules in do_setusercontext may have
1713 * generated messages, so if this in an interactive
1714 * login then display them too.
1715 */
Darren Tuckera2a3ed02004-09-11 23:09:53 +10001716 if (!check_quietlogin(s, command))
Darren Tucker0a44d1e2004-07-01 09:48:29 +10001717 display_loginmsg();
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001718#endif /* HAVE_OSF_SIA */
1719 }
1720
Darren Tucker69687f42004-09-11 22:17:26 +10001721#ifdef USE_PAM
Darren Tucker48554152005-04-21 19:50:55 +10001722 if (options.use_pam && !options.use_login && !is_pam_session_open()) {
1723 debug3("PAM session not opened, exiting");
Darren Tucker69687f42004-09-11 22:17:26 +10001724 display_loginmsg();
1725 exit(254);
1726 }
1727#endif
1728
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001729 /*
1730 * Get the shell from the password data. An empty shell field is
1731 * legal, and means /bin/sh.
1732 */
1733 shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
Ben Lindstrom46767602002-12-23 02:26:08 +00001734
1735 /*
1736 * Make sure $SHELL points to the shell from the password file,
1737 * even if shell is overridden from login.conf
1738 */
1739 env = do_setup_env(s, shell);
1740
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001741#ifdef HAVE_LOGIN_CAP
1742 shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);
1743#endif
1744
Damien Millerad833b32000-08-23 10:46:23 +10001745 /* we have to stash the hostname before we close our socket. */
1746 if (options.use_login)
Ben Lindstromf15a3862001-04-05 23:32:17 +00001747 hostname = get_remote_name_or_ip(utmp_len,
Damien Miller3a961dc2003-06-03 10:25:48 +10001748 options.use_dns);
Damien Millerb38eff82000-04-01 11:09:21 +10001749 /*
1750 * Close the connection descriptors; note that this is the child, and
1751 * the server will still have the socket open, and it is important
1752 * that we do not shutdown it. Note that the descriptors cannot be
1753 * closed before building the environment, as we call
1754 * get_remote_ipaddr there.
1755 */
Darren Tucker23bc8d02004-02-06 16:24:31 +11001756 child_close_fds();
Damien Millerb38eff82000-04-01 11:09:21 +10001757
Damien Millerb38eff82000-04-01 11:09:21 +10001758 /*
Damien Miller05eda432002-02-10 18:32:28 +11001759 * Must take new environment into use so that .ssh/rc,
1760 * /etc/ssh/sshrc and xauth are run in the proper environment.
Damien Millerb38eff82000-04-01 11:09:21 +10001761 */
1762 environ = env;
1763
Darren Tucker3c78c5e2004-01-23 22:03:10 +11001764#if defined(KRB5) && defined(USE_AFS)
Darren Tucker22ef5082003-12-31 11:37:34 +11001765 /*
1766 * At this point, we check to see if AFS is active and if we have
1767 * a valid Kerberos 5 TGT. If so, it seems like a good idea to see
1768 * if we can (and need to) extend the ticket into an AFS token. If
1769 * we don't do this, we run into potential problems if the user's
1770 * home directory is in AFS and it's not world-readable.
1771 */
1772
1773 if (options.kerberos_get_afs_token && k_hasafs() &&
Damien Miller0dc1bef2005-07-17 17:22:45 +10001774 (s->authctxt->krb5_ctx != NULL)) {
Darren Tucker22ef5082003-12-31 11:37:34 +11001775 char cell[64];
1776
1777 debug("Getting AFS token");
1778
1779 k_setpag();
1780
1781 if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
1782 krb5_afslog(s->authctxt->krb5_ctx,
1783 s->authctxt->krb5_fwd_ccache, cell, NULL);
1784
1785 krb5_afslog_home(s->authctxt->krb5_ctx,
1786 s->authctxt->krb5_fwd_ccache, NULL, NULL, pw->pw_dir);
1787 }
1788#endif
1789
Damien Miller788f2122005-11-05 15:14:59 +11001790 /* Change current directory to the user's home directory. */
Damien Miller139d4cd2001-10-10 15:07:44 +10001791 if (chdir(pw->pw_dir) < 0) {
Damien Miller6051c942008-06-16 07:53:16 +10001792 /* Suppress missing homedir warning for chroot case */
Damien Miller139d4cd2001-10-10 15:07:44 +10001793#ifdef HAVE_LOGIN_CAP
Damien Miller6051c942008-06-16 07:53:16 +10001794 r = login_getcapbool(lc, "requirehome", 0);
Damien Miller139d4cd2001-10-10 15:07:44 +10001795#endif
Damien Miller7aa46ec2010-06-26 09:37:57 +10001796 if (r || options.chroot_directory == NULL ||
1797 strcasecmp(options.chroot_directory, "none") == 0)
Damien Miller6051c942008-06-16 07:53:16 +10001798 fprintf(stderr, "Could not chdir to home "
1799 "directory %s: %s\n", pw->pw_dir,
1800 strerror(errno));
1801 if (r)
1802 exit(1);
Damien Miller139d4cd2001-10-10 15:07:44 +10001803 }
1804
Damien Millera1939002008-03-15 17:27:58 +11001805 closefrom(STDERR_FILENO + 1);
1806
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001807 if (!options.use_login)
1808 do_rc_files(s, shell);
Ben Lindstromde71cda2001-03-24 00:43:26 +00001809
1810 /* restore SIGPIPE for child */
Damien Miller9ab00b42006-08-05 12:40:11 +10001811 signal(SIGPIPE, SIG_DFL);
Ben Lindstromde71cda2001-03-24 00:43:26 +00001812
Darren Tuckerd6b06a92010-01-08 17:09:11 +11001813 if (s->is_subsystem == SUBSYSTEM_INT_SFTP_ERROR) {
1814 printf("This service allows sftp connections only.\n");
1815 fflush(NULL);
1816 exit(1);
1817 } else if (s->is_subsystem == SUBSYSTEM_INT_SFTP) {
Damien Millerdfc24252008-02-10 22:29:40 +11001818 extern int optind, optreset;
1819 int i;
1820 char *p, *args;
1821
Darren Tuckerac46a912009-06-21 17:55:23 +10001822 setproctitle("%s@%s", s->pw->pw_name, INTERNAL_SFTP_NAME);
Damien Millerd58f5602008-11-03 19:20:49 +11001823 args = xstrdup(command ? command : "sftp-server");
Damien Millerdfc24252008-02-10 22:29:40 +11001824 for (i = 0, (p = strtok(args, " ")); p; (p = strtok(NULL, " ")))
1825 if (i < ARGV_MAX - 1)
1826 argv[i++] = p;
1827 argv[i] = NULL;
1828 optind = optreset = 1;
1829 __progname = argv[0];
Darren Tucker4d6656b2009-10-24 15:04:12 +11001830#ifdef WITH_SELINUX
1831 ssh_selinux_change_context("sftpd_t");
1832#endif
Damien Millerd8cb1f12008-02-10 22:40:12 +11001833 exit(sftp_server_main(i, argv, s->pw));
Damien Millerdfc24252008-02-10 22:29:40 +11001834 }
1835
Darren Tucker695ed392009-10-07 09:02:18 +11001836 fflush(NULL);
1837
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001838 if (options.use_login) {
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00001839 launch_login(pw, hostname);
1840 /* NEVERREACHED */
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001841 }
1842
1843 /* Get the last component of the shell name. */
1844 if ((shell0 = strrchr(shell, '/')) != NULL)
1845 shell0++;
1846 else
1847 shell0 = shell;
1848
Damien Millerb38eff82000-04-01 11:09:21 +10001849 /*
1850 * If we have no command, execute the shell. In this case, the shell
1851 * name to be passed in argv[0] is preceded by '-' to indicate that
1852 * this is a login shell.
1853 */
1854 if (!command) {
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001855 char argv0[256];
Damien Millerb38eff82000-04-01 11:09:21 +10001856
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001857 /* Start the shell. Set initial character to '-'. */
1858 argv0[0] = '-';
Damien Millerb38eff82000-04-01 11:09:21 +10001859
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001860 if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1)
1861 >= sizeof(argv0) - 1) {
1862 errno = EINVAL;
Damien Millerb38eff82000-04-01 11:09:21 +10001863 perror(shell);
1864 exit(1);
Damien Millerb38eff82000-04-01 11:09:21 +10001865 }
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001866
1867 /* Execute the shell. */
1868 argv[0] = argv0;
1869 argv[1] = NULL;
1870 execve(shell, argv, env);
1871
1872 /* Executing the shell failed. */
1873 perror(shell);
1874 exit(1);
Damien Millerb38eff82000-04-01 11:09:21 +10001875 }
1876 /*
1877 * Execute the command using the user's shell. This uses the -c
1878 * option to execute the command.
1879 */
Ben Lindstrom4e97e852002-02-19 21:50:43 +00001880 argv[0] = (char *) shell0;
Damien Millerb38eff82000-04-01 11:09:21 +10001881 argv[1] = "-c";
1882 argv[2] = (char *) command;
1883 argv[3] = NULL;
1884 execve(shell, argv, env);
1885 perror(shell);
1886 exit(1);
1887}
1888
Damien Miller7207f642008-05-19 15:34:50 +10001889void
1890session_unused(int id)
1891{
1892 debug3("%s: session id %d unused", __func__, id);
1893 if (id >= options.max_sessions ||
1894 id >= sessions_nalloc) {
1895 fatal("%s: insane session id %d (max %d nalloc %d)",
1896 __func__, id, options.max_sessions, sessions_nalloc);
1897 }
1898 bzero(&sessions[id], sizeof(*sessions));
1899 sessions[id].self = id;
1900 sessions[id].used = 0;
1901 sessions[id].chanid = -1;
1902 sessions[id].ptyfd = -1;
1903 sessions[id].ttyfd = -1;
1904 sessions[id].ptymaster = -1;
1905 sessions[id].x11_chanids = NULL;
1906 sessions[id].next_unused = sessions_first_unused;
1907 sessions_first_unused = id;
1908}
1909
Damien Millerb38eff82000-04-01 11:09:21 +10001910Session *
1911session_new(void)
1912{
Damien Miller7207f642008-05-19 15:34:50 +10001913 Session *s, *tmp;
1914
1915 if (sessions_first_unused == -1) {
1916 if (sessions_nalloc >= options.max_sessions)
1917 return NULL;
1918 debug2("%s: allocate (allocated %d max %d)",
1919 __func__, sessions_nalloc, options.max_sessions);
1920 tmp = xrealloc(sessions, sessions_nalloc + 1,
1921 sizeof(*sessions));
1922 if (tmp == NULL) {
1923 error("%s: cannot allocate %d sessions",
1924 __func__, sessions_nalloc + 1);
1925 return NULL;
Damien Millerb38eff82000-04-01 11:09:21 +10001926 }
Damien Miller7207f642008-05-19 15:34:50 +10001927 sessions = tmp;
1928 session_unused(sessions_nalloc++);
Damien Millerb38eff82000-04-01 11:09:21 +10001929 }
Damien Miller7207f642008-05-19 15:34:50 +10001930
1931 if (sessions_first_unused >= sessions_nalloc ||
1932 sessions_first_unused < 0) {
1933 fatal("%s: insane first_unused %d max %d nalloc %d",
1934 __func__, sessions_first_unused, options.max_sessions,
1935 sessions_nalloc);
Damien Millerb38eff82000-04-01 11:09:21 +10001936 }
Damien Miller7207f642008-05-19 15:34:50 +10001937
1938 s = &sessions[sessions_first_unused];
1939 if (s->used) {
1940 fatal("%s: session %d already used",
1941 __func__, sessions_first_unused);
1942 }
1943 sessions_first_unused = s->next_unused;
1944 s->used = 1;
1945 s->next_unused = -1;
1946 debug("session_new: session %d", s->self);
1947
1948 return s;
Damien Millerb38eff82000-04-01 11:09:21 +10001949}
1950
Ben Lindstrombba81212001-06-25 05:01:22 +00001951static void
Damien Millerb38eff82000-04-01 11:09:21 +10001952session_dump(void)
1953{
1954 int i;
Damien Miller7207f642008-05-19 15:34:50 +10001955 for (i = 0; i < sessions_nalloc; i++) {
Damien Millerb38eff82000-04-01 11:09:21 +10001956 Session *s = &sessions[i];
Damien Miller7207f642008-05-19 15:34:50 +10001957
1958 debug("dump: used %d next_unused %d session %d %p "
1959 "channel %d pid %ld",
Damien Millerb38eff82000-04-01 11:09:21 +10001960 s->used,
Damien Miller7207f642008-05-19 15:34:50 +10001961 s->next_unused,
Damien Millerb38eff82000-04-01 11:09:21 +10001962 s->self,
1963 s,
1964 s->chanid,
Ben Lindstromce0f6342002-06-11 16:42:49 +00001965 (long)s->pid);
Damien Millerb38eff82000-04-01 11:09:21 +10001966 }
1967}
1968
Damien Millerefb4afe2000-04-12 18:45:05 +10001969int
Ben Lindstrombddd5512001-07-04 04:53:53 +00001970session_open(Authctxt *authctxt, int chanid)
Damien Millerefb4afe2000-04-12 18:45:05 +10001971{
1972 Session *s = session_new();
1973 debug("session_open: channel %d", chanid);
1974 if (s == NULL) {
1975 error("no more sessions");
1976 return 0;
1977 }
Ben Lindstrombddd5512001-07-04 04:53:53 +00001978 s->authctxt = authctxt;
1979 s->pw = authctxt->pw;
Damien Miller3e3b5142003-11-17 21:13:40 +11001980 if (s->pw == NULL || !authctxt->valid)
Kevin Steves43cdef32001-02-11 14:12:08 +00001981 fatal("no user for session %d", s->self);
Damien Millerbd483e72000-04-30 10:00:53 +10001982 debug("session_open: session %d: link with channel %d", s->self, chanid);
1983 s->chanid = chanid;
Damien Millerefb4afe2000-04-12 18:45:05 +10001984 return 1;
1985}
1986
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00001987Session *
1988session_by_tty(char *tty)
1989{
1990 int i;
Damien Miller7207f642008-05-19 15:34:50 +10001991 for (i = 0; i < sessions_nalloc; i++) {
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00001992 Session *s = &sessions[i];
1993 if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) {
1994 debug("session_by_tty: session %d tty %s", i, tty);
1995 return s;
1996 }
1997 }
1998 debug("session_by_tty: unknown tty %.100s", tty);
1999 session_dump();
2000 return NULL;
2001}
2002
Ben Lindstrombba81212001-06-25 05:01:22 +00002003static Session *
Damien Millerefb4afe2000-04-12 18:45:05 +10002004session_by_channel(int id)
2005{
2006 int i;
Damien Miller7207f642008-05-19 15:34:50 +10002007 for (i = 0; i < sessions_nalloc; i++) {
Damien Millerefb4afe2000-04-12 18:45:05 +10002008 Session *s = &sessions[i];
2009 if (s->used && s->chanid == id) {
Damien Miller7207f642008-05-19 15:34:50 +10002010 debug("session_by_channel: session %d channel %d",
2011 i, id);
Damien Millerefb4afe2000-04-12 18:45:05 +10002012 return s;
2013 }
2014 }
2015 debug("session_by_channel: unknown channel %d", id);
2016 session_dump();
2017 return NULL;
2018}
2019
Ben Lindstrombba81212001-06-25 05:01:22 +00002020static Session *
Damien Miller2b9b0452005-07-17 17:19:24 +10002021session_by_x11_channel(int id)
2022{
2023 int i, j;
2024
Damien Miller7207f642008-05-19 15:34:50 +10002025 for (i = 0; i < sessions_nalloc; i++) {
Damien Miller2b9b0452005-07-17 17:19:24 +10002026 Session *s = &sessions[i];
2027
2028 if (s->x11_chanids == NULL || !s->used)
2029 continue;
2030 for (j = 0; s->x11_chanids[j] != -1; j++) {
2031 if (s->x11_chanids[j] == id) {
2032 debug("session_by_x11_channel: session %d "
2033 "channel %d", s->self, id);
2034 return s;
2035 }
2036 }
2037 }
2038 debug("session_by_x11_channel: unknown channel %d", id);
2039 session_dump();
2040 return NULL;
2041}
2042
2043static Session *
Damien Millerefb4afe2000-04-12 18:45:05 +10002044session_by_pid(pid_t pid)
2045{
2046 int i;
Ben Lindstromce0f6342002-06-11 16:42:49 +00002047 debug("session_by_pid: pid %ld", (long)pid);
Damien Miller7207f642008-05-19 15:34:50 +10002048 for (i = 0; i < sessions_nalloc; i++) {
Damien Millerefb4afe2000-04-12 18:45:05 +10002049 Session *s = &sessions[i];
2050 if (s->used && s->pid == pid)
2051 return s;
2052 }
Ben Lindstromce0f6342002-06-11 16:42:49 +00002053 error("session_by_pid: unknown pid %ld", (long)pid);
Damien Millerefb4afe2000-04-12 18:45:05 +10002054 session_dump();
2055 return NULL;
2056}
2057
Ben Lindstrombba81212001-06-25 05:01:22 +00002058static int
Damien Millerefb4afe2000-04-12 18:45:05 +10002059session_window_change_req(Session *s)
2060{
2061 s->col = packet_get_int();
2062 s->row = packet_get_int();
2063 s->xpixel = packet_get_int();
2064 s->ypixel = packet_get_int();
Damien Miller48b03fc2002-01-22 23:11:40 +11002065 packet_check_eom();
Damien Millerefb4afe2000-04-12 18:45:05 +10002066 pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
2067 return 1;
2068}
2069
Ben Lindstrombba81212001-06-25 05:01:22 +00002070static int
Damien Millerefb4afe2000-04-12 18:45:05 +10002071session_pty_req(Session *s)
2072{
Ben Lindstrom46c16222000-12-22 01:43:59 +00002073 u_int len;
Ben Lindstromae8e2d32001-04-14 23:13:02 +00002074 int n_bytes;
Ben Lindstrom6328ab32002-03-22 02:54:23 +00002075
Ben Lindstrom49c12602001-06-13 04:37:36 +00002076 if (no_pty_flag) {
2077 debug("Allocating a pty not permitted for this authentication.");
Damien Millerf6d9e222000-06-18 14:50:44 +10002078 return 0;
Ben Lindstrom49c12602001-06-13 04:37:36 +00002079 }
2080 if (s->ttyfd != -1) {
2081 packet_disconnect("Protocol error: you already have a pty.");
Damien Miller4af51302000-04-16 11:18:38 +10002082 return 0;
Ben Lindstrom49c12602001-06-13 04:37:36 +00002083 }
2084
Damien Millerefb4afe2000-04-12 18:45:05 +10002085 s->term = packet_get_string(&len);
Ben Lindstrom49c12602001-06-13 04:37:36 +00002086
2087 if (compat20) {
2088 s->col = packet_get_int();
2089 s->row = packet_get_int();
2090 } else {
2091 s->row = packet_get_int();
2092 s->col = packet_get_int();
2093 }
Damien Millerefb4afe2000-04-12 18:45:05 +10002094 s->xpixel = packet_get_int();
2095 s->ypixel = packet_get_int();
2096
2097 if (strcmp(s->term, "") == 0) {
2098 xfree(s->term);
2099 s->term = NULL;
2100 }
Ben Lindstrom49c12602001-06-13 04:37:36 +00002101
Damien Millerefb4afe2000-04-12 18:45:05 +10002102 /* Allocate a pty and open it. */
Ben Lindstrom49c12602001-06-13 04:37:36 +00002103 debug("Allocating pty.");
Damien Miller7207f642008-05-19 15:34:50 +10002104 if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty,
2105 sizeof(s->tty)))) {
Ben Lindstrom49c12602001-06-13 04:37:36 +00002106 if (s->term)
2107 xfree(s->term);
Damien Millerefb4afe2000-04-12 18:45:05 +10002108 s->term = NULL;
2109 s->ptyfd = -1;
2110 s->ttyfd = -1;
2111 error("session_pty_req: session %d alloc failed", s->self);
Damien Miller4af51302000-04-16 11:18:38 +10002112 return 0;
Damien Millerefb4afe2000-04-12 18:45:05 +10002113 }
2114 debug("session_pty_req: session %d alloc %s", s->self, s->tty);
Ben Lindstrom49c12602001-06-13 04:37:36 +00002115
2116 /* for SSH1 the tty modes length is not given */
2117 if (!compat20)
2118 n_bytes = packet_remaining();
2119 tty_parse_modes(s->ttyfd, &n_bytes);
2120
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00002121 if (!use_privsep)
2122 pty_setowner(s->pw, s->tty);
Ben Lindstrom49c12602001-06-13 04:37:36 +00002123
2124 /* Set window size from the packet. */
Damien Millerefb4afe2000-04-12 18:45:05 +10002125 pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
2126
Damien Miller48b03fc2002-01-22 23:11:40 +11002127 packet_check_eom();
Damien Millere247cc42000-05-07 12:03:14 +10002128 session_proctitle(s);
Damien Millerefb4afe2000-04-12 18:45:05 +10002129 return 1;
2130}
2131
Ben Lindstrombba81212001-06-25 05:01:22 +00002132static int
Damien Millerbd483e72000-04-30 10:00:53 +10002133session_subsystem_req(Session *s)
2134{
Damien Millerae452462001-10-10 15:08:06 +10002135 struct stat st;
Ben Lindstrom46c16222000-12-22 01:43:59 +00002136 u_int len;
Damien Millerbd483e72000-04-30 10:00:53 +10002137 int success = 0;
Damien Miller917f9b62006-07-10 20:36:47 +10002138 char *prog, *cmd, *subsys = packet_get_string(&len);
Damien Millereccb9de2005-06-17 12:59:34 +10002139 u_int i;
Damien Millerbd483e72000-04-30 10:00:53 +10002140
Damien Miller48b03fc2002-01-22 23:11:40 +11002141 packet_check_eom();
Damien Miller1b2b61e2010-06-26 09:47:43 +10002142 logit("subsystem request for %.100s by user %s", subsys,
2143 s->pw->pw_name);
Damien Millerbd483e72000-04-30 10:00:53 +10002144
Damien Millerf6d9e222000-06-18 14:50:44 +10002145 for (i = 0; i < options.num_subsystems; i++) {
Damien Millerae452462001-10-10 15:08:06 +10002146 if (strcmp(subsys, options.subsystem_name[i]) == 0) {
Damien Miller917f9b62006-07-10 20:36:47 +10002147 prog = options.subsystem_command[i];
2148 cmd = options.subsystem_args[i];
Darren Tuckerc3dc4042010-01-08 17:09:50 +11002149 if (strcmp(INTERNAL_SFTP_NAME, prog) == 0) {
Damien Millerdfc24252008-02-10 22:29:40 +11002150 s->is_subsystem = SUBSYSTEM_INT_SFTP;
Darren Tuckerc3dc4042010-01-08 17:09:50 +11002151 debug("subsystem: %s", prog);
Damien Millerdfc24252008-02-10 22:29:40 +11002152 } else {
Darren Tuckerc3dc4042010-01-08 17:09:50 +11002153 if (stat(prog, &st) < 0)
2154 debug("subsystem: cannot stat %s: %s",
2155 prog, strerror(errno));
Damien Millerdfc24252008-02-10 22:29:40 +11002156 s->is_subsystem = SUBSYSTEM_EXT;
Darren Tuckerc3dc4042010-01-08 17:09:50 +11002157 debug("subsystem: exec() %s", cmd);
Damien Millerae452462001-10-10 15:08:06 +10002158 }
Damien Miller7207f642008-05-19 15:34:50 +10002159 success = do_exec(s, cmd) == 0;
Damien Miller5fab4b92002-02-05 12:15:07 +11002160 break;
Damien Millerf6d9e222000-06-18 14:50:44 +10002161 }
2162 }
2163
2164 if (!success)
Damien Miller996acd22003-04-09 20:59:48 +10002165 logit("subsystem request for %.100s failed, subsystem not found",
Damien Millerae452462001-10-10 15:08:06 +10002166 subsys);
Damien Millerf6d9e222000-06-18 14:50:44 +10002167
Damien Millerbd483e72000-04-30 10:00:53 +10002168 xfree(subsys);
2169 return success;
2170}
2171
Ben Lindstrombba81212001-06-25 05:01:22 +00002172static int
Damien Millerbd483e72000-04-30 10:00:53 +10002173session_x11_req(Session *s)
2174{
Ben Lindstrom768176b2001-06-09 01:29:12 +00002175 int success;
Damien Millerbd483e72000-04-30 10:00:53 +10002176
Damien Miller2b9b0452005-07-17 17:19:24 +10002177 if (s->auth_proto != NULL || s->auth_data != NULL) {
2178 error("session_x11_req: session %d: "
Darren Tucker63551872005-12-20 16:14:15 +11002179 "x11 forwarding already active", s->self);
Damien Miller2b9b0452005-07-17 17:19:24 +10002180 return 0;
2181 }
Damien Millerbd483e72000-04-30 10:00:53 +10002182 s->single_connection = packet_get_char();
2183 s->auth_proto = packet_get_string(NULL);
2184 s->auth_data = packet_get_string(NULL);
2185 s->screen = packet_get_int();
Damien Miller48b03fc2002-01-22 23:11:40 +11002186 packet_check_eom();
Damien Millerbd483e72000-04-30 10:00:53 +10002187
Ben Lindstrom768176b2001-06-09 01:29:12 +00002188 success = session_setup_x11fwd(s);
2189 if (!success) {
Damien Millerbd483e72000-04-30 10:00:53 +10002190 xfree(s->auth_proto);
2191 xfree(s->auth_data);
Ben Lindstrom88259fb2001-06-12 00:21:34 +00002192 s->auth_proto = NULL;
2193 s->auth_data = NULL;
Damien Millerbd483e72000-04-30 10:00:53 +10002194 }
Ben Lindstrom768176b2001-06-09 01:29:12 +00002195 return success;
Damien Millerbd483e72000-04-30 10:00:53 +10002196}
2197
Ben Lindstrombba81212001-06-25 05:01:22 +00002198static int
Damien Millerf6d9e222000-06-18 14:50:44 +10002199session_shell_req(Session *s)
2200{
Damien Miller48b03fc2002-01-22 23:11:40 +11002201 packet_check_eom();
Damien Miller7207f642008-05-19 15:34:50 +10002202 return do_exec(s, NULL) == 0;
Damien Millerf6d9e222000-06-18 14:50:44 +10002203}
2204
Ben Lindstrombba81212001-06-25 05:01:22 +00002205static int
Damien Millerf6d9e222000-06-18 14:50:44 +10002206session_exec_req(Session *s)
2207{
Damien Miller7207f642008-05-19 15:34:50 +10002208 u_int len, success;
2209
Damien Millerf6d9e222000-06-18 14:50:44 +10002210 char *command = packet_get_string(&len);
Damien Miller48b03fc2002-01-22 23:11:40 +11002211 packet_check_eom();
Damien Miller7207f642008-05-19 15:34:50 +10002212 success = do_exec(s, command) == 0;
Ben Lindstrom0a7ca6c2001-06-21 03:17:42 +00002213 xfree(command);
Damien Miller7207f642008-05-19 15:34:50 +10002214 return success;
Damien Millerf6d9e222000-06-18 14:50:44 +10002215}
2216
Ben Lindstrombba81212001-06-25 05:01:22 +00002217static int
Damien Miller54c45982003-05-15 10:20:13 +10002218session_break_req(Session *s)
2219{
Damien Miller54c45982003-05-15 10:20:13 +10002220
Darren Tucker1f8311c2004-05-13 16:39:33 +10002221 packet_get_int(); /* ignored */
Damien Miller54c45982003-05-15 10:20:13 +10002222 packet_check_eom();
2223
Damien Miller7207f642008-05-19 15:34:50 +10002224 if (s->ttyfd == -1 || tcsendbreak(s->ttyfd, 0) < 0)
Damien Miller54c45982003-05-15 10:20:13 +10002225 return 0;
Damien Miller54c45982003-05-15 10:20:13 +10002226 return 1;
2227}
2228
2229static int
Darren Tucker46bc0752004-05-02 22:11:30 +10002230session_env_req(Session *s)
2231{
2232 char *name, *val;
2233 u_int name_len, val_len, i;
2234
2235 name = packet_get_string(&name_len);
2236 val = packet_get_string(&val_len);
2237 packet_check_eom();
2238
2239 /* Don't set too many environment variables */
2240 if (s->num_env > 128) {
2241 debug2("Ignoring env request %s: too many env vars", name);
2242 goto fail;
2243 }
2244
2245 for (i = 0; i < options.num_accept_env; i++) {
2246 if (match_pattern(name, options.accept_env[i])) {
2247 debug2("Setting env %d: %s=%s", s->num_env, name, val);
Damien Miller36812092006-03-26 14:22:47 +11002248 s->env = xrealloc(s->env, s->num_env + 1,
2249 sizeof(*s->env));
Darren Tucker46bc0752004-05-02 22:11:30 +10002250 s->env[s->num_env].name = name;
2251 s->env[s->num_env].val = val;
2252 s->num_env++;
2253 return (1);
2254 }
2255 }
2256 debug2("Ignoring env request %s: disallowed name", name);
2257
2258 fail:
2259 xfree(name);
2260 xfree(val);
2261 return (0);
2262}
2263
2264static int
Damien Miller0bc1bd82000-11-13 22:57:25 +11002265session_auth_agent_req(Session *s)
2266{
2267 static int called = 0;
Damien Miller48b03fc2002-01-22 23:11:40 +11002268 packet_check_eom();
Damien Miller4f755cd2008-05-19 14:57:41 +10002269 if (no_agent_forwarding_flag || !options.allow_agent_forwarding) {
Ben Lindstrom14920292000-11-21 21:24:55 +00002270 debug("session_auth_agent_req: no_agent_forwarding_flag");
2271 return 0;
2272 }
Damien Miller0bc1bd82000-11-13 22:57:25 +11002273 if (called) {
2274 return 0;
2275 } else {
2276 called = 1;
2277 return auth_input_request_forwarding(s->pw);
2278 }
2279}
2280
Damien Millerc7ef63d2002-02-05 12:21:42 +11002281int
2282session_input_channel_req(Channel *c, const char *rtype)
Damien Millerefb4afe2000-04-12 18:45:05 +10002283{
Damien Millerefb4afe2000-04-12 18:45:05 +10002284 int success = 0;
Damien Millerefb4afe2000-04-12 18:45:05 +10002285 Session *s;
Damien Millerefb4afe2000-04-12 18:45:05 +10002286
Damien Millerc7ef63d2002-02-05 12:21:42 +11002287 if ((s = session_by_channel(c->self)) == NULL) {
Damien Miller996acd22003-04-09 20:59:48 +10002288 logit("session_input_channel_req: no session %d req %.100s",
Damien Millerc7ef63d2002-02-05 12:21:42 +11002289 c->self, rtype);
2290 return 0;
2291 }
2292 debug("session_input_channel_req: session %d req %s", s->self, rtype);
Damien Millerefb4afe2000-04-12 18:45:05 +10002293
2294 /*
Ben Lindstromfc9b07d2001-03-22 01:27:23 +00002295 * a session is in LARVAL state until a shell, a command
2296 * or a subsystem is executed
Damien Millerefb4afe2000-04-12 18:45:05 +10002297 */
2298 if (c->type == SSH_CHANNEL_LARVAL) {
2299 if (strcmp(rtype, "shell") == 0) {
Damien Millerf6d9e222000-06-18 14:50:44 +10002300 success = session_shell_req(s);
Damien Millerefb4afe2000-04-12 18:45:05 +10002301 } else if (strcmp(rtype, "exec") == 0) {
Damien Millerf6d9e222000-06-18 14:50:44 +10002302 success = session_exec_req(s);
Damien Millerefb4afe2000-04-12 18:45:05 +10002303 } else if (strcmp(rtype, "pty-req") == 0) {
Darren Tucker82a3d2b2007-02-19 22:10:25 +11002304 success = session_pty_req(s);
Damien Millerbd483e72000-04-30 10:00:53 +10002305 } else if (strcmp(rtype, "x11-req") == 0) {
2306 success = session_x11_req(s);
Damien Miller0bc1bd82000-11-13 22:57:25 +11002307 } else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) {
2308 success = session_auth_agent_req(s);
Damien Millerbd483e72000-04-30 10:00:53 +10002309 } else if (strcmp(rtype, "subsystem") == 0) {
2310 success = session_subsystem_req(s);
Darren Tucker46bc0752004-05-02 22:11:30 +10002311 } else if (strcmp(rtype, "env") == 0) {
2312 success = session_env_req(s);
Damien Millerefb4afe2000-04-12 18:45:05 +10002313 }
2314 }
2315 if (strcmp(rtype, "window-change") == 0) {
2316 success = session_window_change_req(s);
Damien Millera6b1d162004-06-30 22:41:07 +10002317 } else if (strcmp(rtype, "break") == 0) {
2318 success = session_break_req(s);
Damien Millerefb4afe2000-04-12 18:45:05 +10002319 }
Damien Millera6b1d162004-06-30 22:41:07 +10002320
Damien Millerc7ef63d2002-02-05 12:21:42 +11002321 return success;
Damien Millerefb4afe2000-04-12 18:45:05 +10002322}
2323
2324void
Damien Miller8853ca52010-06-26 10:00:14 +10002325session_set_fds(Session *s, int fdin, int fdout, int fderr, int ignore_fderr,
2326 int is_tty)
Damien Millerefb4afe2000-04-12 18:45:05 +10002327{
2328 if (!compat20)
2329 fatal("session_set_fds: called for proto != 2.0");
2330 /*
2331 * now that have a child and a pipe to the child,
2332 * we can activate our channel and register the fd's
2333 */
2334 if (s->chanid == -1)
2335 fatal("no channel for session %d", s->self);
2336 channel_set_fds(s->chanid,
2337 fdout, fdin, fderr,
Damien Miller8853ca52010-06-26 10:00:14 +10002338 ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
Darren Tuckered3cdc02008-06-16 23:29:18 +10002339 1, is_tty, CHAN_SES_WINDOW_DEFAULT);
Damien Millerefb4afe2000-04-12 18:45:05 +10002340}
2341
Ben Lindstrom7eaf8e42001-06-13 04:35:43 +00002342/*
2343 * Function to perform pty cleanup. Also called if we get aborted abnormally
2344 * (e.g., due to a dropped connection).
2345 */
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00002346void
Darren Tucker3e33cec2003-10-02 16:12:36 +10002347session_pty_cleanup2(Session *s)
Damien Millerb38eff82000-04-01 11:09:21 +10002348{
Ben Lindstrom7eaf8e42001-06-13 04:35:43 +00002349 if (s == NULL) {
2350 error("session_pty_cleanup: no session");
2351 return;
2352 }
2353 if (s->ttyfd == -1)
Damien Millerb38eff82000-04-01 11:09:21 +10002354 return;
2355
Kevin Steves43cdef32001-02-11 14:12:08 +00002356 debug("session_pty_cleanup: session %d release %s", s->self, s->tty);
Damien Millerb38eff82000-04-01 11:09:21 +10002357
Damien Millerb38eff82000-04-01 11:09:21 +10002358 /* Record that the user has logged out. */
Ben Lindstrom7eaf8e42001-06-13 04:35:43 +00002359 if (s->pid != 0)
Tim Ricee06ae4a2002-02-24 17:56:46 -08002360 record_logout(s->pid, s->tty, s->pw->pw_name);
Damien Millerb38eff82000-04-01 11:09:21 +10002361
2362 /* Release the pseudo-tty. */
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00002363 if (getuid() == 0)
2364 pty_release(s->tty);
Damien Millerb38eff82000-04-01 11:09:21 +10002365
2366 /*
2367 * Close the server side of the socket pairs. We must do this after
2368 * the pty cleanup, so that another process doesn't get this pty
2369 * while we're still cleaning up.
2370 */
Damien Miller7207f642008-05-19 15:34:50 +10002371 if (s->ptymaster != -1 && close(s->ptymaster) < 0)
2372 error("close(s->ptymaster/%d): %s",
2373 s->ptymaster, strerror(errno));
Damien Miller0585d512001-10-12 11:35:50 +10002374
2375 /* unlink pty from session */
2376 s->ttyfd = -1;
Damien Millerb38eff82000-04-01 11:09:21 +10002377}
Damien Millerefb4afe2000-04-12 18:45:05 +10002378
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00002379void
Darren Tucker3e33cec2003-10-02 16:12:36 +10002380session_pty_cleanup(Session *s)
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00002381{
Darren Tucker3e33cec2003-10-02 16:12:36 +10002382 PRIVSEP(session_pty_cleanup2(s));
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00002383}
2384
Damien Miller5a80bba2002-09-04 16:39:02 +10002385static char *
2386sig2name(int sig)
2387{
2388#define SSH_SIG(x) if (sig == SIG ## x) return #x
2389 SSH_SIG(ABRT);
2390 SSH_SIG(ALRM);
2391 SSH_SIG(FPE);
2392 SSH_SIG(HUP);
2393 SSH_SIG(ILL);
2394 SSH_SIG(INT);
2395 SSH_SIG(KILL);
2396 SSH_SIG(PIPE);
2397 SSH_SIG(QUIT);
2398 SSH_SIG(SEGV);
2399 SSH_SIG(TERM);
2400 SSH_SIG(USR1);
2401 SSH_SIG(USR2);
2402#undef SSH_SIG
2403 return "SIG@openssh.com";
2404}
2405
Ben Lindstrombba81212001-06-25 05:01:22 +00002406static void
Damien Miller2b9b0452005-07-17 17:19:24 +10002407session_close_x11(int id)
2408{
2409 Channel *c;
2410
Damien Millerd47c62a2005-12-13 19:33:57 +11002411 if ((c = channel_by_id(id)) == NULL) {
Damien Miller2b9b0452005-07-17 17:19:24 +10002412 debug("session_close_x11: x11 channel %d missing", id);
2413 } else {
2414 /* Detach X11 listener */
2415 debug("session_close_x11: detach x11 channel %d", id);
2416 channel_cancel_cleanup(id);
2417 if (c->ostate != CHAN_OUTPUT_CLOSED)
2418 chan_mark_dead(c);
2419 }
2420}
2421
2422static void
2423session_close_single_x11(int id, void *arg)
2424{
2425 Session *s;
2426 u_int i;
2427
2428 debug3("session_close_single_x11: channel %d", id);
2429 channel_cancel_cleanup(id);
Darren Tucker82a3d2b2007-02-19 22:10:25 +11002430 if ((s = session_by_x11_channel(id)) == NULL)
Damien Miller2b9b0452005-07-17 17:19:24 +10002431 fatal("session_close_single_x11: no x11 channel %d", id);
2432 for (i = 0; s->x11_chanids[i] != -1; i++) {
2433 debug("session_close_single_x11: session %d: "
2434 "closing channel %d", s->self, s->x11_chanids[i]);
2435 /*
2436 * The channel "id" is already closing, but make sure we
2437 * close all of its siblings.
2438 */
2439 if (s->x11_chanids[i] != id)
2440 session_close_x11(s->x11_chanids[i]);
2441 }
2442 xfree(s->x11_chanids);
2443 s->x11_chanids = NULL;
2444 if (s->display) {
2445 xfree(s->display);
2446 s->display = NULL;
2447 }
2448 if (s->auth_proto) {
2449 xfree(s->auth_proto);
2450 s->auth_proto = NULL;
2451 }
2452 if (s->auth_data) {
2453 xfree(s->auth_data);
2454 s->auth_data = NULL;
2455 }
2456 if (s->auth_display) {
2457 xfree(s->auth_display);
2458 s->auth_display = NULL;
2459 }
2460}
2461
2462static void
Damien Millerefb4afe2000-04-12 18:45:05 +10002463session_exit_message(Session *s, int status)
2464{
2465 Channel *c;
Damien Millerf3dcf1f2002-02-08 22:06:48 +11002466
2467 if ((c = channel_lookup(s->chanid)) == NULL)
Ben Lindstrom7eaf8e42001-06-13 04:35:43 +00002468 fatal("session_exit_message: session %d: no channel %d",
Damien Millerefb4afe2000-04-12 18:45:05 +10002469 s->self, s->chanid);
Ben Lindstromce0f6342002-06-11 16:42:49 +00002470 debug("session_exit_message: session %d channel %d pid %ld",
2471 s->self, s->chanid, (long)s->pid);
Damien Millerefb4afe2000-04-12 18:45:05 +10002472
2473 if (WIFEXITED(status)) {
Damien Millerf3dcf1f2002-02-08 22:06:48 +11002474 channel_request_start(s->chanid, "exit-status", 0);
Damien Millerefb4afe2000-04-12 18:45:05 +10002475 packet_put_int(WEXITSTATUS(status));
2476 packet_send();
2477 } else if (WIFSIGNALED(status)) {
Damien Millerf3dcf1f2002-02-08 22:06:48 +11002478 channel_request_start(s->chanid, "exit-signal", 0);
Damien Miller5a80bba2002-09-04 16:39:02 +10002479 packet_put_cstring(sig2name(WTERMSIG(status)));
Damien Millerf3c6cf12000-05-17 22:08:29 +10002480#ifdef WCOREDUMP
Damien Miller767087b2008-03-07 18:32:42 +11002481 packet_put_char(WCOREDUMP(status)? 1 : 0);
Damien Millerf3c6cf12000-05-17 22:08:29 +10002482#else /* WCOREDUMP */
2483 packet_put_char(0);
2484#endif /* WCOREDUMP */
Damien Millerefb4afe2000-04-12 18:45:05 +10002485 packet_put_cstring("");
2486 packet_put_cstring("");
2487 packet_send();
2488 } else {
2489 /* Some weird exit cause. Just exit. */
2490 packet_disconnect("wait returned status %04x.", status);
2491 }
2492
2493 /* disconnect channel */
2494 debug("session_exit_message: release channel %d", s->chanid);
Damien Miller39eda6e2005-11-05 14:52:50 +11002495
2496 /*
2497 * Adjust cleanup callback attachment to send close messages when
Damien Millerc91e5562006-03-26 13:58:55 +11002498 * the channel gets EOF. The session will be then be closed
Damien Miller39eda6e2005-11-05 14:52:50 +11002499 * by session_close_by_channel when the childs close their fds.
2500 */
2501 channel_register_cleanup(c->self, session_close_by_channel, 1);
2502
Damien Miller166fca82000-04-20 07:42:21 +10002503 /*
2504 * emulate a write failure with 'chan_write_failed', nobody will be
2505 * interested in data we write.
2506 * Note that we must not call 'chan_read_failed', since there could
2507 * be some more data waiting in the pipe.
2508 */
Damien Millerbd483e72000-04-30 10:00:53 +10002509 if (c->ostate != CHAN_OUTPUT_CLOSED)
2510 chan_write_failed(c);
Damien Millerefb4afe2000-04-12 18:45:05 +10002511}
2512
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00002513void
Ben Lindstrom7eaf8e42001-06-13 04:35:43 +00002514session_close(Session *s)
Damien Millerefb4afe2000-04-12 18:45:05 +10002515{
Damien Millereccb9de2005-06-17 12:59:34 +10002516 u_int i;
Darren Tucker46bc0752004-05-02 22:11:30 +10002517
Ben Lindstromce0f6342002-06-11 16:42:49 +00002518 debug("session_close: session %d pid %ld", s->self, (long)s->pid);
Darren Tucker3e33cec2003-10-02 16:12:36 +10002519 if (s->ttyfd != -1)
Ben Lindstrom7eaf8e42001-06-13 04:35:43 +00002520 session_pty_cleanup(s);
Damien Millerefb4afe2000-04-12 18:45:05 +10002521 if (s->term)
2522 xfree(s->term);
2523 if (s->display)
2524 xfree(s->display);
Damien Miller2b9b0452005-07-17 17:19:24 +10002525 if (s->x11_chanids)
2526 xfree(s->x11_chanids);
Damien Miller512bccb2002-02-05 12:11:02 +11002527 if (s->auth_display)
2528 xfree(s->auth_display);
Damien Millerefb4afe2000-04-12 18:45:05 +10002529 if (s->auth_data)
2530 xfree(s->auth_data);
2531 if (s->auth_proto)
2532 xfree(s->auth_proto);
Damien Millerd5fe0ba2006-08-30 11:07:39 +10002533 if (s->env != NULL) {
2534 for (i = 0; i < s->num_env; i++) {
2535 xfree(s->env[i].name);
2536 xfree(s->env[i].val);
2537 }
Darren Tucker46bc0752004-05-02 22:11:30 +10002538 xfree(s->env);
Damien Millerd5fe0ba2006-08-30 11:07:39 +10002539 }
Damien Millere247cc42000-05-07 12:03:14 +10002540 session_proctitle(s);
Damien Miller7207f642008-05-19 15:34:50 +10002541 session_unused(s->self);
Damien Millerefb4afe2000-04-12 18:45:05 +10002542}
2543
2544void
2545session_close_by_pid(pid_t pid, int status)
2546{
2547 Session *s = session_by_pid(pid);
2548 if (s == NULL) {
Ben Lindstromce0f6342002-06-11 16:42:49 +00002549 debug("session_close_by_pid: no session for pid %ld",
2550 (long)pid);
Damien Millerefb4afe2000-04-12 18:45:05 +10002551 return;
2552 }
2553 if (s->chanid != -1)
2554 session_exit_message(s, status);
Damien Miller39eda6e2005-11-05 14:52:50 +11002555 if (s->ttyfd != -1)
2556 session_pty_cleanup(s);
Tim Rice83d2f5f2006-02-07 15:17:44 -08002557 s->pid = 0;
Damien Millerefb4afe2000-04-12 18:45:05 +10002558}
2559
2560/*
2561 * this is called when a channel dies before
2562 * the session 'child' itself dies
2563 */
2564void
2565session_close_by_channel(int id, void *arg)
2566{
2567 Session *s = session_by_channel(id);
Damien Miller39eda6e2005-11-05 14:52:50 +11002568 u_int i;
Damien Miller2b9b0452005-07-17 17:19:24 +10002569
Damien Millerefb4afe2000-04-12 18:45:05 +10002570 if (s == NULL) {
Damien Miller3ec27592001-10-12 11:35:04 +10002571 debug("session_close_by_channel: no session for id %d", id);
Damien Millerefb4afe2000-04-12 18:45:05 +10002572 return;
2573 }
Ben Lindstromce0f6342002-06-11 16:42:49 +00002574 debug("session_close_by_channel: channel %d child %ld",
2575 id, (long)s->pid);
Damien Miller3ec27592001-10-12 11:35:04 +10002576 if (s->pid != 0) {
Damien Miller3ec27592001-10-12 11:35:04 +10002577 debug("session_close_by_channel: channel %d: has child", id);
Damien Miller0585d512001-10-12 11:35:50 +10002578 /*
2579 * delay detach of session, but release pty, since
2580 * the fd's to the child are already closed
2581 */
Darren Tucker3e33cec2003-10-02 16:12:36 +10002582 if (s->ttyfd != -1)
Damien Miller0585d512001-10-12 11:35:50 +10002583 session_pty_cleanup(s);
Damien Miller3ec27592001-10-12 11:35:04 +10002584 return;
2585 }
2586 /* detach by removing callback */
Damien Millerefb4afe2000-04-12 18:45:05 +10002587 channel_cancel_cleanup(s->chanid);
Damien Miller39eda6e2005-11-05 14:52:50 +11002588
2589 /* Close any X11 listeners associated with this session */
2590 if (s->x11_chanids != NULL) {
2591 for (i = 0; s->x11_chanids[i] != -1; i++) {
2592 session_close_x11(s->x11_chanids[i]);
2593 s->x11_chanids[i] = -1;
2594 }
2595 }
2596
Damien Millerefb4afe2000-04-12 18:45:05 +10002597 s->chanid = -1;
Damien Miller52b77be2001-10-10 15:14:37 +10002598 session_close(s);
2599}
2600
2601void
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00002602session_destroy_all(void (*closefunc)(Session *))
Damien Miller52b77be2001-10-10 15:14:37 +10002603{
2604 int i;
Damien Miller7207f642008-05-19 15:34:50 +10002605 for (i = 0; i < sessions_nalloc; i++) {
Damien Miller52b77be2001-10-10 15:14:37 +10002606 Session *s = &sessions[i];
Ben Lindstrom7a2073c2002-03-22 02:30:41 +00002607 if (s->used) {
2608 if (closefunc != NULL)
2609 closefunc(s);
2610 else
2611 session_close(s);
2612 }
Damien Miller52b77be2001-10-10 15:14:37 +10002613 }
Damien Millerefb4afe2000-04-12 18:45:05 +10002614}
2615
Ben Lindstrombba81212001-06-25 05:01:22 +00002616static char *
Damien Millere247cc42000-05-07 12:03:14 +10002617session_tty_list(void)
2618{
2619 static char buf[1024];
2620 int i;
Damien Millera8ed44b2003-01-10 09:53:12 +11002621 char *cp;
2622
Damien Millere247cc42000-05-07 12:03:14 +10002623 buf[0] = '\0';
Damien Miller7207f642008-05-19 15:34:50 +10002624 for (i = 0; i < sessions_nalloc; i++) {
Damien Millere247cc42000-05-07 12:03:14 +10002625 Session *s = &sessions[i];
2626 if (s->used && s->ttyfd != -1) {
Damien Miller787b2ec2003-11-21 23:56:47 +11002627
Damien Millera8ed44b2003-01-10 09:53:12 +11002628 if (strncmp(s->tty, "/dev/", 5) != 0) {
2629 cp = strrchr(s->tty, '/');
2630 cp = (cp == NULL) ? s->tty : cp + 1;
2631 } else
2632 cp = s->tty + 5;
Damien Miller787b2ec2003-11-21 23:56:47 +11002633
Damien Millere247cc42000-05-07 12:03:14 +10002634 if (buf[0] != '\0')
2635 strlcat(buf, ",", sizeof buf);
Damien Millera8ed44b2003-01-10 09:53:12 +11002636 strlcat(buf, cp, sizeof buf);
Damien Millere247cc42000-05-07 12:03:14 +10002637 }
2638 }
2639 if (buf[0] == '\0')
2640 strlcpy(buf, "notty", sizeof buf);
2641 return buf;
2642}
2643
2644void
2645session_proctitle(Session *s)
2646{
2647 if (s->pw == NULL)
2648 error("no user for session %d", s->self);
2649 else
2650 setproctitle("%s@%s", s->pw->pw_name, session_tty_list());
2651}
2652
Ben Lindstrom768176b2001-06-09 01:29:12 +00002653int
2654session_setup_x11fwd(Session *s)
2655{
Ben Lindstrom768176b2001-06-09 01:29:12 +00002656 struct stat st;
Kevin Steves366298c2001-12-19 17:58:01 +00002657 char display[512], auth_display[512];
2658 char hostname[MAXHOSTNAMELEN];
Damien Miller2b9b0452005-07-17 17:19:24 +10002659 u_int i;
Ben Lindstrom768176b2001-06-09 01:29:12 +00002660
2661 if (no_x11_forwarding_flag) {
2662 packet_send_debug("X11 forwarding disabled in user configuration file.");
2663 return 0;
2664 }
2665 if (!options.x11_forwarding) {
2666 debug("X11 forwarding disabled in server configuration file.");
2667 return 0;
2668 }
2669 if (!options.xauth_location ||
2670 (stat(options.xauth_location, &st) == -1)) {
2671 packet_send_debug("No xauth program; cannot forward with spoofing.");
2672 return 0;
2673 }
Ben Lindstrom699776e2001-06-21 03:14:49 +00002674 if (options.use_login) {
2675 packet_send_debug("X11 forwarding disabled; "
2676 "not compatible with UseLogin=yes.");
2677 return 0;
2678 }
Ben Lindstrom2bcdf062001-06-13 04:41:41 +00002679 if (s->display != NULL) {
Ben Lindstrom768176b2001-06-09 01:29:12 +00002680 debug("X11 display already set.");
2681 return 0;
2682 }
Ben Lindstroma9d2c892002-06-23 21:48:28 +00002683 if (x11_create_display_inet(options.x11_display_offset,
2684 options.x11_use_localhost, s->single_connection,
Damien Miller2b9b0452005-07-17 17:19:24 +10002685 &s->display_number, &s->x11_chanids) == -1) {
Ben Lindstrom2bcdf062001-06-13 04:41:41 +00002686 debug("x11_create_display_inet failed.");
Ben Lindstrom768176b2001-06-09 01:29:12 +00002687 return 0;
2688 }
Damien Miller2b9b0452005-07-17 17:19:24 +10002689 for (i = 0; s->x11_chanids[i] != -1; i++) {
2690 channel_register_cleanup(s->x11_chanids[i],
Damien Miller39eda6e2005-11-05 14:52:50 +11002691 session_close_single_x11, 0);
Damien Miller2b9b0452005-07-17 17:19:24 +10002692 }
Kevin Steves366298c2001-12-19 17:58:01 +00002693
2694 /* Set up a suitable value for the DISPLAY variable. */
2695 if (gethostname(hostname, sizeof(hostname)) < 0)
2696 fatal("gethostname: %.100s", strerror(errno));
2697 /*
2698 * auth_display must be used as the displayname when the
2699 * authorization entry is added with xauth(1). This will be
2700 * different than the DISPLAY string for localhost displays.
2701 */
Damien Miller95c249f2002-02-05 12:11:34 +11002702 if (options.x11_use_localhost) {
Ben Lindstroma9d2c892002-06-23 21:48:28 +00002703 snprintf(display, sizeof display, "localhost:%u.%u",
Kevin Steves366298c2001-12-19 17:58:01 +00002704 s->display_number, s->screen);
Ben Lindstroma9d2c892002-06-23 21:48:28 +00002705 snprintf(auth_display, sizeof auth_display, "unix:%u.%u",
Damien Miller512bccb2002-02-05 12:11:02 +11002706 s->display_number, s->screen);
Kevin Steves366298c2001-12-19 17:58:01 +00002707 s->display = xstrdup(display);
Damien Miller512bccb2002-02-05 12:11:02 +11002708 s->auth_display = xstrdup(auth_display);
Kevin Steves366298c2001-12-19 17:58:01 +00002709 } else {
2710#ifdef IPADDR_IN_DISPLAY
2711 struct hostent *he;
2712 struct in_addr my_addr;
2713
2714 he = gethostbyname(hostname);
2715 if (he == NULL) {
2716 error("Can't get IP address for X11 DISPLAY.");
2717 packet_send_debug("Can't get IP address for X11 DISPLAY.");
2718 return 0;
2719 }
2720 memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr));
Ben Lindstroma9d2c892002-06-23 21:48:28 +00002721 snprintf(display, sizeof display, "%.50s:%u.%u", inet_ntoa(my_addr),
Kevin Steves366298c2001-12-19 17:58:01 +00002722 s->display_number, s->screen);
2723#else
Ben Lindstroma9d2c892002-06-23 21:48:28 +00002724 snprintf(display, sizeof display, "%.400s:%u.%u", hostname,
Kevin Steves366298c2001-12-19 17:58:01 +00002725 s->display_number, s->screen);
2726#endif
2727 s->display = xstrdup(display);
Damien Miller512bccb2002-02-05 12:11:02 +11002728 s->auth_display = xstrdup(display);
Kevin Steves366298c2001-12-19 17:58:01 +00002729 }
2730
Ben Lindstrom768176b2001-06-09 01:29:12 +00002731 return 1;
2732}
2733
Ben Lindstrombba81212001-06-25 05:01:22 +00002734static void
Ben Lindstromdb65e8f2001-01-19 04:26:52 +00002735do_authenticated2(Authctxt *authctxt)
Damien Millerefb4afe2000-04-12 18:45:05 +10002736{
Ben Lindstrombddd5512001-07-04 04:53:53 +00002737 server_loop2(authctxt);
Darren Tucker3e33cec2003-10-02 16:12:36 +10002738}
2739
2740void
2741do_cleanup(Authctxt *authctxt)
2742{
2743 static int called = 0;
2744
2745 debug("do_cleanup");
2746
2747 /* no cleanup if we're in the child for login shell */
2748 if (is_child)
2749 return;
2750
2751 /* avoid double cleanup */
2752 if (called)
2753 return;
2754 called = 1;
2755
Darren Tucker9142e1c2007-08-16 23:28:04 +10002756 if (authctxt == NULL)
Darren Tucker3e33cec2003-10-02 16:12:36 +10002757 return;
Darren Tucker9142e1c2007-08-16 23:28:04 +10002758
2759#ifdef USE_PAM
2760 if (options.use_pam) {
2761 sshpam_cleanup();
2762 sshpam_thread_cleanup();
2763 }
2764#endif
2765
2766 if (!authctxt->authenticated)
2767 return;
2768
Darren Tucker3e33cec2003-10-02 16:12:36 +10002769#ifdef KRB5
2770 if (options.kerberos_ticket_cleanup &&
2771 authctxt->krb5_ctx)
2772 krb5_cleanup_proc(authctxt);
Darren Tucker0efd1552003-08-26 11:49:55 +10002773#endif
Darren Tucker3e33cec2003-10-02 16:12:36 +10002774
2775#ifdef GSSAPI
2776 if (compat20 && options.gss_cleanup_creds)
2777 ssh_gssapi_cleanup_creds();
2778#endif
2779
2780 /* remove agent socket */
2781 auth_sock_cleanup_proc(authctxt->pw);
2782
2783 /*
2784 * Cleanup ptys/utmp only if privsep is disabled,
2785 * or if running in monitor.
2786 */
2787 if (!use_privsep || mm_is_monitor())
2788 session_destroy_all(session_pty_cleanup2);
Damien Millerefb4afe2000-04-12 18:45:05 +10002789}