blob: c06d914e6f24897e8984f61003464f65a4e8e9a5 [file] [log] [blame]
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001/*
Damien Miller95def091999-11-25 00:26:21 +11002 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 * All rights reserved
5 * Created: Fri Mar 17 17:09:28 1995 ylo
6 * This program is the ssh daemon. It listens for connections from clients, and
7 * performs authentication, executes use commands or shell, and forwards
8 * information to/from the application to the user client over an encrypted
9 * connection. This can also handle forwarding of X11, TCP/IP, and authentication
10 * agent connections.
11 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100012
13#include "includes.h"
Damien Miller32b3cf21999-12-26 10:21:48 +110014RCSID("$Id: sshd.c,v 1.41 1999/12/25 23:21:48 damien Exp $");
Damien Miller50945fa1999-12-09 10:31:37 +110015
Damien Miller6ae00d61999-12-14 15:43:03 +110016#ifdef HAVE_POLL_H
17# include <poll.h>
18#else /* HAVE_POLL_H */
19# ifdef HAVE_SYS_POLL_H
20# include <sys/poll.h>
21# endif /* HAVE_SYS_POLL_H */
22#endif /* HAVE_POLL_H */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100023
24#include "xmalloc.h"
25#include "rsa.h"
26#include "ssh.h"
27#include "pty.h"
28#include "packet.h"
29#include "buffer.h"
30#include "cipher.h"
31#include "mpaux.h"
32#include "servconf.h"
33#include "uidswap.h"
34#include "compat.h"
35
36#ifdef LIBWRAP
37#include <tcpd.h>
38#include <syslog.h>
39int allow_severity = LOG_INFO;
40int deny_severity = LOG_WARNING;
41#endif /* LIBWRAP */
42
43#ifndef O_NOCTTY
44#define O_NOCTTY 0
45#endif
46
Damien Millerd4a8b7e1999-10-27 13:42:43 +100047/* Local Xauthority file. */
Damien Miller5ce662a1999-11-11 17:57:39 +110048static char *xauthfile = NULL;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100049
50/* Server configuration options. */
51ServerOptions options;
52
53/* Name of the server configuration file. */
54char *config_file_name = SERVER_CONFIG_FILE;
55
Damien Miller95def091999-11-25 00:26:21 +110056/*
57 * Debug mode flag. This can be set on the command line. If debug
58 * mode is enabled, extra debugging output will be sent to the system
59 * log, the daemon will not go to background, and will exit after processing
60 * the first connection.
61 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100062int debug_flag = 0;
63
64/* Flag indicating that the daemon is being started from inetd. */
65int inetd_flag = 0;
66
Damien Miller5ce662a1999-11-11 17:57:39 +110067/* debug goes to stderr unless inetd_flag is set */
68int log_stderr = 0;
69
Damien Millerd4a8b7e1999-10-27 13:42:43 +100070/* argv[0] without path. */
71char *av0;
72
73/* Saved arguments to main(). */
74char **saved_argv;
75
Damien Miller5428f641999-11-25 11:54:57 +110076/*
77 * This is set to the socket that the server is listening; this is used in
78 * the SIGHUP signal handler.
79 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100080int listen_sock;
81
Damien Miller5428f641999-11-25 11:54:57 +110082/*
83 * the client's version string, passed by sshd2 in compat mode. if != NULL,
84 * sshd will skip the version-number exchange
85 */
Damien Miller95def091999-11-25 00:26:21 +110086char *client_version_string = NULL;
87
88/* Flags set in auth-rsa from authorized_keys flags. These are set in auth-rsa.c. */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100089int no_port_forwarding_flag = 0;
90int no_agent_forwarding_flag = 0;
91int no_x11_forwarding_flag = 0;
92int no_pty_flag = 0;
Damien Miller95def091999-11-25 00:26:21 +110093
94/* RSA authentication "command=" option. */
95char *forced_command = NULL;
96
97/* RSA authentication "environment=" options. */
98struct envstring *custom_environment = NULL;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100099
100/* Session id for the current session. */
101unsigned char session_id[16];
102
Damien Miller5428f641999-11-25 11:54:57 +1100103/*
104 * Any really sensitive data in the application is contained in this
105 * structure. The idea is that this structure could be locked into memory so
106 * that the pages do not get written into swap. However, there are some
107 * problems. The private key contains BIGNUMs, and we do not (in principle)
108 * have access to the internals of them, and locking just the structure is
109 * not very useful. Currently, memory locking is not implemented.
110 */
Damien Miller95def091999-11-25 00:26:21 +1100111struct {
112 RSA *private_key; /* Private part of server key. */
113 RSA *host_key; /* Private part of host key. */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000114} sensitive_data;
115
Damien Miller5428f641999-11-25 11:54:57 +1100116/*
117 * Flag indicating whether the current session key has been used. This flag
118 * is set whenever the key is used, and cleared when the key is regenerated.
119 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000120int key_used = 0;
121
122/* This is set to true when SIGHUP is received. */
123int received_sighup = 0;
124
125/* Public side of the server key. This value is regenerated regularly with
126 the private key. */
127RSA *public_key;
128
129/* Prototypes for various functions defined later in this file. */
Damien Miller2ccf6611999-11-15 15:25:10 +1100130void do_connection();
131void do_authentication(char *user);
Damien Miller95def091999-11-25 00:26:21 +1100132void do_authloop(struct passwd * pw);
Damien Miller2ccf6611999-11-15 15:25:10 +1100133void do_fake_authloop(char *user);
Damien Miller95def091999-11-25 00:26:21 +1100134void do_authenticated(struct passwd * pw);
135void do_exec_pty(const char *command, int ptyfd, int ttyfd,
136 const char *ttyname, struct passwd * pw, const char *term,
137 const char *display, const char *auth_proto,
138 const char *auth_data);
139void do_exec_no_pty(const char *command, struct passwd * pw,
140 const char *display, const char *auth_proto,
141 const char *auth_data);
142void do_child(const char *command, struct passwd * pw, const char *term,
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000143 const char *display, const char *auth_proto,
144 const char *auth_data, const char *ttyname);
Damien Miller2ccf6611999-11-15 15:25:10 +1100145
Damien Miller06230761999-10-28 14:03:14 +1000146#ifdef HAVE_LIBPAM
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000147static int pamconv(int num_msg, const struct pam_message **msg,
Damien Miller95def091999-11-25 00:26:21 +1100148 struct pam_response **resp, void *appdata_ptr);
Damien Miller2e1b0821999-12-25 10:11:29 +1100149int do_pam_auth(const char *user, const char *password);
Damien Millerbf1c9b21999-12-09 10:16:54 +1100150void do_pam_account(char *username, char *remote_user);
151void do_pam_session(char *username, char *ttyname);
Damien Miller332e67f1999-10-27 23:42:05 +1000152void pam_cleanup_proc(void *context);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000153
154static struct pam_conv conv = {
Damien Miller95def091999-11-25 00:26:21 +1100155 pamconv,
156 NULL
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000157};
Damien Miller332e67f1999-10-27 23:42:05 +1000158struct pam_handle_t *pamh = NULL;
159const char *pampasswd = NULL;
Damien Miller356a0b01999-11-08 15:30:59 +1100160char *pamconv_msg = NULL;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000161
162static int pamconv(int num_msg, const struct pam_message **msg,
Damien Miller9072e181999-11-25 10:42:08 +1100163 struct pam_response **resp, void *appdata_ptr)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000164{
Damien Miller95def091999-11-25 00:26:21 +1100165 struct pam_response *reply;
166 int count;
167 size_t msg_len;
168 char *p;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000169
Damien Miller95def091999-11-25 00:26:21 +1100170 /* PAM will free this later */
171 reply = malloc(num_msg * sizeof(*reply));
172 if (reply == NULL)
173 return PAM_CONV_ERR;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000174
Damien Miller95def091999-11-25 00:26:21 +1100175 for(count = 0; count < num_msg; count++) {
176 switch (msg[count]->msg_style) {
177 case PAM_PROMPT_ECHO_OFF:
178 if (pampasswd == NULL) {
179 free(reply);
180 return PAM_CONV_ERR;
181 }
182 reply[count].resp_retcode = PAM_SUCCESS;
183 reply[count].resp = xstrdup(pampasswd);
184 break;
Damien Miller5bbbd361999-11-19 07:56:21 +1100185
Damien Miller95def091999-11-25 00:26:21 +1100186 case PAM_TEXT_INFO:
187 reply[count].resp_retcode = PAM_SUCCESS;
188 reply[count].resp = xstrdup("");
189
190 if (msg[count]->msg == NULL)
191 break;
192
193 debug("Adding PAM message: %s", msg[count]->msg);
194
195 msg_len = strlen(msg[count]->msg);
196 if (pamconv_msg) {
197 size_t n = strlen(pamconv_msg);
198 pamconv_msg = xrealloc(pamconv_msg, n + msg_len + 2);
199 p = pamconv_msg + n;
200 } else {
201 pamconv_msg = p = xmalloc(msg_len + 2);
202 }
203 memcpy(p, msg[count]->msg, msg_len);
204 p[msg_len] = '\n';
205 p[msg_len + 1] = '\0';
206 break;
207
208 case PAM_PROMPT_ECHO_ON:
209 case PAM_ERROR_MSG:
210 default:
211 free(reply);
212 return PAM_CONV_ERR;
213 }
Damien Miller356a0b01999-11-08 15:30:59 +1100214 }
Damien Miller332e67f1999-10-27 23:42:05 +1000215
Damien Miller95def091999-11-25 00:26:21 +1100216 *resp = reply;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000217
Damien Miller95def091999-11-25 00:26:21 +1100218 return PAM_SUCCESS;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000219}
220
221void pam_cleanup_proc(void *context)
222{
Damien Miller95def091999-11-25 00:26:21 +1100223 int pam_retval;
224
225 if (pamh != NULL)
226 {
227 pam_retval = pam_close_session((pam_handle_t *)pamh, 0);
228 if (pam_retval != PAM_SUCCESS) {
229 log("Cannot close PAM session: %.200s",
230 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
231 }
232
233 pam_retval = pam_end((pam_handle_t *)pamh, pam_retval);
234 if (pam_retval != PAM_SUCCESS) {
235 log("Cannot release PAM authentication: %.200s",
236 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
237 }
238 }
Damien Miller332e67f1999-10-27 23:42:05 +1000239}
240
Damien Miller2e1b0821999-12-25 10:11:29 +1100241int do_pam_auth(const char *user, const char *password)
242{
243 int pam_retval;
244
245 pampasswd = password;
246
247 pam_retval = pam_authenticate((pam_handle_t *)pamh, 0);
248 if (pam_retval == PAM_SUCCESS) {
249 log("PAM Password authentication accepted for user \"%.100s\"", user);
250 return 1;
251 } else {
Damien Miller32b3cf21999-12-26 10:21:48 +1100252 /* Don't log failure for auth attempts with empty password */
253 if (password[0] != '\0')
254 log("PAM Password authentication for \"%.100s\" failed: %s",
255 user, PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
Damien Miller2e1b0821999-12-25 10:11:29 +1100256 return 0;
257 }
258}
259
Damien Millerbf1c9b21999-12-09 10:16:54 +1100260void do_pam_account(char *username, char *remote_user)
Damien Miller332e67f1999-10-27 23:42:05 +1000261{
Damien Miller95def091999-11-25 00:26:21 +1100262 int pam_retval;
Damien Miller332e67f1999-10-27 23:42:05 +1000263
Damien Millerdc33fc31999-12-04 20:24:48 +1100264 debug("PAM setting rhost to \"%.200s\"", get_canonical_hostname());
265 pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RHOST,
266 get_canonical_hostname());
267 if (pam_retval != PAM_SUCCESS) {
268 log("PAM set rhost failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
269 do_fake_authloop(username);
Damien Miller95def091999-11-25 00:26:21 +1100270 }
271
272 if (remote_user != NULL) {
273 debug("PAM setting ruser to \"%.200s\"", remote_user);
274 pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RUSER, remote_user);
275 if (pam_retval != PAM_SUCCESS) {
276 log("PAM set ruser failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
277 do_fake_authloop(username);
278 }
279 }
280
281 pam_retval = pam_acct_mgmt((pam_handle_t *)pamh, 0);
282 if (pam_retval != PAM_SUCCESS) {
283 log("PAM rejected by account configuration: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
284 do_fake_authloop(username);
285 }
Damien Millerbf1c9b21999-12-09 10:16:54 +1100286}
287
288void do_pam_session(char *username, char *ttyname)
289{
290 int pam_retval;
291
292 if (ttyname != NULL) {
293 debug("PAM setting tty to \"%.200s\"", ttyname);
294 pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_TTY, ttyname);
295 if (pam_retval != PAM_SUCCESS)
296 fatal("PAM set tty failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
297 }
Damien Miller95def091999-11-25 00:26:21 +1100298
299 pam_retval = pam_open_session((pam_handle_t *)pamh, 0);
Damien Millerbf1c9b21999-12-09 10:16:54 +1100300 if (pam_retval != PAM_SUCCESS)
301 fatal("PAM session setup failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000302}
Damien Miller06230761999-10-28 14:03:14 +1000303#endif /* HAVE_LIBPAM */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000304
Damien Miller95def091999-11-25 00:26:21 +1100305/*
306 * Signal handler for SIGHUP. Sshd execs itself when it receives SIGHUP;
307 * the effect is to reread the configuration file (and to regenerate
308 * the server key).
309 */
310void
311sighup_handler(int sig)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000312{
Damien Miller95def091999-11-25 00:26:21 +1100313 received_sighup = 1;
314 signal(SIGHUP, sighup_handler);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000315}
316
Damien Miller95def091999-11-25 00:26:21 +1100317/*
318 * Called from the main program after receiving SIGHUP.
319 * Restarts the server.
320 */
321void
322sighup_restart()
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000323{
Damien Miller95def091999-11-25 00:26:21 +1100324 log("Received SIGHUP; restarting.");
325 close(listen_sock);
326 execv(saved_argv[0], saved_argv);
327 log("RESTART FAILED: av0='%s', error: %s.", av0, strerror(errno));
328 exit(1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000329}
330
Damien Miller95def091999-11-25 00:26:21 +1100331/*
332 * Generic signal handler for terminating signals in the master daemon.
333 * These close the listen socket; not closing it seems to cause "Address
334 * already in use" problems on some machines, which is inconvenient.
335 */
336void
337sigterm_handler(int sig)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000338{
Damien Miller95def091999-11-25 00:26:21 +1100339 log("Received signal %d; terminating.", sig);
340 close(listen_sock);
341 exit(255);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000342}
343
Damien Miller95def091999-11-25 00:26:21 +1100344/*
345 * SIGCHLD handler. This is called whenever a child dies. This will then
346 * reap any zombies left by exited c.
347 */
348void
349main_sigchld_handler(int sig)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000350{
Damien Miller95def091999-11-25 00:26:21 +1100351 int save_errno = errno;
352 int status;
Damien Miller431f66b1999-11-21 18:31:57 +1100353
Damien Miller95def091999-11-25 00:26:21 +1100354 while (waitpid(-1, &status, WNOHANG) > 0)
355 ;
Damien Miller431f66b1999-11-21 18:31:57 +1100356
Damien Miller95def091999-11-25 00:26:21 +1100357 signal(SIGCHLD, main_sigchld_handler);
358 errno = save_errno;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000359}
360
Damien Miller95def091999-11-25 00:26:21 +1100361/*
362 * Signal handler for the alarm after the login grace period has expired.
363 */
364void
365grace_alarm_handler(int sig)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000366{
Damien Miller95def091999-11-25 00:26:21 +1100367 /* Close the connection. */
368 packet_close();
369
370 /* Log error and exit. */
371 fatal("Timeout before authentication for %s.", get_remote_ipaddr());
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000372}
373
Damien Miller95def091999-11-25 00:26:21 +1100374/*
375 * convert ssh auth msg type into description
376 */
377char *
378get_authname(int type)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000379{
Damien Miller95def091999-11-25 00:26:21 +1100380 switch (type) {
381 case SSH_CMSG_AUTH_PASSWORD:
382 return "password";
383 case SSH_CMSG_AUTH_RSA:
384 return "rsa";
385 case SSH_CMSG_AUTH_RHOSTS_RSA:
386 return "rhosts-rsa";
387 case SSH_CMSG_AUTH_RHOSTS:
388 return "rhosts";
389#ifdef KRB4
390 case SSH_CMSG_AUTH_KERBEROS:
391 return "kerberos";
392#endif
393#ifdef SKEY
394 case SSH_CMSG_AUTH_TIS_RESPONSE:
395 return "s/key";
396#endif
397 }
398 fatal("get_authname: unknown auth %d: internal error", type);
399 return NULL;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000400}
401
Damien Miller95def091999-11-25 00:26:21 +1100402/*
403 * Signal handler for the key regeneration alarm. Note that this
404 * alarm only occurs in the daemon waiting for connections, and it does not
405 * do anything with the private key or random state before forking.
406 * Thus there should be no concurrency control/asynchronous execution
407 * problems.
408 */
409void
410key_regeneration_alarm(int sig)
411{
412 int save_errno = errno;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000413
Damien Miller95def091999-11-25 00:26:21 +1100414 /* Check if we should generate a new key. */
415 if (key_used) {
416 /* This should really be done in the background. */
417 log("Generating new %d bit RSA key.", options.server_key_bits);
418
419 if (sensitive_data.private_key != NULL)
420 RSA_free(sensitive_data.private_key);
421 sensitive_data.private_key = RSA_new();
422
423 if (public_key != NULL)
424 RSA_free(public_key);
425 public_key = RSA_new();
426
427 rsa_generate_key(sensitive_data.private_key, public_key,
428 options.server_key_bits);
429 arc4random_stir();
430 key_used = 0;
431 log("RSA key generation complete.");
432 }
433 /* Reschedule the alarm. */
434 signal(SIGALRM, key_regeneration_alarm);
435 alarm(options.key_regeneration_time);
436 errno = save_errno;
437}
438
439/*
440 * Main program for the daemon.
441 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000442int
443main(int ac, char **av)
444{
Damien Miller95def091999-11-25 00:26:21 +1100445 extern char *optarg;
446 extern int optind;
447 int opt, aux, sock_in, sock_out, newsock, i, pid, on = 1;
448 int remote_major, remote_minor;
449 int silentrsa = 0;
Damien Miller50945fa1999-12-09 10:31:37 +1100450 struct pollfd fds;
Damien Miller95def091999-11-25 00:26:21 +1100451 struct sockaddr_in sin;
452 char buf[100]; /* Must not be larger than remote_version. */
453 char remote_version[100]; /* Must be at least as big as buf. */
454 const char *remote_ip;
455 int remote_port;
456 char *comment;
457 FILE *f;
458 struct linger linger;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000459
Damien Miller95def091999-11-25 00:26:21 +1100460 /* Save argv[0]. */
461 saved_argv = av;
462 if (strchr(av[0], '/'))
463 av0 = strrchr(av[0], '/') + 1;
464 else
465 av0 = av[0];
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000466
Damien Miller95def091999-11-25 00:26:21 +1100467 /* Initialize configuration options to their default values. */
468 initialize_server_options(&options);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000469
Damien Miller95def091999-11-25 00:26:21 +1100470 /* Parse command-line arguments. */
471 while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:diqQ")) != EOF) {
472 switch (opt) {
473 case 'f':
474 config_file_name = optarg;
475 break;
476 case 'd':
477 debug_flag = 1;
478 options.log_level = SYSLOG_LEVEL_DEBUG;
479 break;
480 case 'i':
481 inetd_flag = 1;
482 break;
483 case 'Q':
484 silentrsa = 1;
485 break;
486 case 'q':
487 options.log_level = SYSLOG_LEVEL_QUIET;
488 break;
489 case 'b':
490 options.server_key_bits = atoi(optarg);
491 break;
492 case 'p':
493 options.port = atoi(optarg);
494 break;
495 case 'g':
496 options.login_grace_time = atoi(optarg);
497 break;
498 case 'k':
499 options.key_regeneration_time = atoi(optarg);
500 break;
501 case 'h':
502 options.host_key_file = optarg;
503 break;
504 case 'V':
505 client_version_string = optarg;
506 /* only makes sense with inetd_flag, i.e. no listen() */
507 inetd_flag = 1;
508 break;
509 case '?':
510 default:
511 fprintf(stderr, "sshd version %s\n", SSH_VERSION);
512 fprintf(stderr, "Usage: %s [options]\n", av0);
513 fprintf(stderr, "Options:\n");
Damien Miller5428f641999-11-25 11:54:57 +1100514 fprintf(stderr, " -f file Configuration file (default %s)\n", SERVER_CONFIG_FILE);
Damien Miller95def091999-11-25 00:26:21 +1100515 fprintf(stderr, " -d Debugging mode\n");
516 fprintf(stderr, " -i Started from inetd\n");
517 fprintf(stderr, " -q Quiet (no logging)\n");
518 fprintf(stderr, " -p port Listen on the specified port (default: 22)\n");
519 fprintf(stderr, " -k seconds Regenerate server key every this many seconds (default: 3600)\n");
520 fprintf(stderr, " -g seconds Grace period for authentication (default: 300)\n");
521 fprintf(stderr, " -b bits Size of server RSA key (default: 768 bits)\n");
522 fprintf(stderr, " -h file File from which to read host key (default: %s)\n",
523 HOST_KEY_FILE);
524 exit(1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000525 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000526 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000527
Damien Miller95def091999-11-25 00:26:21 +1100528 /* check if RSA support exists */
529 if (rsa_alive() == 0) {
530 if (silentrsa == 0)
531 printf("sshd: no RSA support in libssl and libcrypto -- exiting. See ssl(8)\n");
532 log("no RSA support in libssl and libcrypto -- exiting. See ssl(8)");
533 exit(1);
534 }
535 /* Read server configuration options from the configuration file. */
536 read_server_config(&options, config_file_name);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000537
Damien Miller95def091999-11-25 00:26:21 +1100538 /* Fill in default values for those options not explicitly set. */
539 fill_default_server_options(&options);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000540
Damien Miller95def091999-11-25 00:26:21 +1100541 /* Check certain values for sanity. */
542 if (options.server_key_bits < 512 ||
543 options.server_key_bits > 32768) {
544 fprintf(stderr, "Bad server key size.\n");
545 exit(1);
546 }
547 if (options.port < 1 || options.port > 65535) {
548 fprintf(stderr, "Bad port number.\n");
549 exit(1);
550 }
551 /* Check that there are no remaining arguments. */
552 if (optind < ac) {
553 fprintf(stderr, "Extra argument %s.\n", av[optind]);
554 exit(1);
555 }
556 /* Force logging to stderr while loading the private host key
557 unless started from inetd */
558 log_init(av0, options.log_level, options.log_facility, !inetd_flag);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000559
Damien Miller95def091999-11-25 00:26:21 +1100560 debug("sshd version %.100s", SSH_VERSION);
Damien Miller2ccf6611999-11-15 15:25:10 +1100561
Damien Miller95def091999-11-25 00:26:21 +1100562 sensitive_data.host_key = RSA_new();
563 errno = 0;
564 /* Load the host key. It must have empty passphrase. */
565 if (!load_private_key(options.host_key_file, "",
566 sensitive_data.host_key, &comment)) {
567 error("Could not load host key: %.200s: %.100s",
568 options.host_key_file, strerror(errno));
569 exit(1);
570 }
571 xfree(comment);
572
573 /* Initialize the log (it is reinitialized below in case we
574 forked). */
575 if (debug_flag && !inetd_flag)
576 log_stderr = 1;
577 log_init(av0, options.log_level, options.log_facility, log_stderr);
578
579 /* If not in debugging mode, and not started from inetd,
580 disconnect from the controlling terminal, and fork. The
581 original process exits. */
582 if (!debug_flag && !inetd_flag) {
583#ifdef TIOCNOTTY
584 int fd;
585#endif /* TIOCNOTTY */
586 if (daemon(0, 0) < 0)
587 fatal("daemon() failed: %.200s", strerror(errno));
588
589 /* Disconnect from the controlling tty. */
590#ifdef TIOCNOTTY
591 fd = open("/dev/tty", O_RDWR | O_NOCTTY);
592 if (fd >= 0) {
593 (void) ioctl(fd, TIOCNOTTY, NULL);
594 close(fd);
595 }
596#endif /* TIOCNOTTY */
597 }
598 /* Reinitialize the log (because of the fork above). */
599 log_init(av0, options.log_level, options.log_facility, log_stderr);
600
601 /* Check that server and host key lengths differ sufficiently.
602 This is necessary to make double encryption work with rsaref.
603 Oh, I hate software patents. I dont know if this can go? Niels */
604 if (options.server_key_bits >
605 BN_num_bits(sensitive_data.host_key->n) - SSH_KEY_BITS_RESERVED &&
606 options.server_key_bits <
607 BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) {
608 options.server_key_bits =
609 BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED;
610 debug("Forcing server key to %d bits to make it differ from host key.",
611 options.server_key_bits);
612 }
613 /* Do not display messages to stdout in RSA code. */
614 rsa_set_verbose(0);
615
616 /* Initialize the random number generator. */
617 arc4random_stir();
618
619 /* Chdir to the root directory so that the current disk can be
620 unmounted if desired. */
621 chdir("/");
622
623 /* Close connection cleanly after attack. */
624 cipher_attack_detected = packet_disconnect;
625
626 /* Start listening for a socket, unless started from inetd. */
627 if (inetd_flag) {
628 int s1, s2;
629 s1 = dup(0); /* Make sure descriptors 0, 1, and 2 are in use. */
630 s2 = dup(s1);
631 sock_in = dup(0);
632 sock_out = dup(1);
633 /* We intentionally do not close the descriptors 0, 1, and 2
634 as our code for setting the descriptors won\'t work
635 if ttyfd happens to be one of those. */
636 debug("inetd sockets after dupping: %d, %d", sock_in, sock_out);
637
638 public_key = RSA_new();
639 sensitive_data.private_key = RSA_new();
640
641 log("Generating %d bit RSA key.", options.server_key_bits);
642 rsa_generate_key(sensitive_data.private_key, public_key,
643 options.server_key_bits);
644 arc4random_stir();
645 log("RSA key generation complete.");
646 } else {
647 /* Create socket for listening. */
648 listen_sock = socket(AF_INET, SOCK_STREAM, 0);
649 if (listen_sock < 0)
650 fatal("socket: %.100s", strerror(errno));
651
652 /* Set socket options. We try to make the port reusable
653 and have it close as fast as possible without waiting
654 in unnecessary wait states on close. */
655 setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on,
656 sizeof(on));
657 linger.l_onoff = 1;
658 linger.l_linger = 5;
659 setsockopt(listen_sock, SOL_SOCKET, SO_LINGER, (void *) &linger,
660 sizeof(linger));
661
Damien Miller95def091999-11-25 00:26:21 +1100662 memset(&sin, 0, sizeof(sin));
663 sin.sin_family = AF_INET;
664 sin.sin_addr = options.listen_addr;
665 sin.sin_port = htons(options.port);
666
Damien Miller95def091999-11-25 00:26:21 +1100667 if (bind(listen_sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) {
668 error("bind: %.100s", strerror(errno));
669 shutdown(listen_sock, SHUT_RDWR);
670 close(listen_sock);
671 fatal("Bind to port %d failed.", options.port);
672 }
673 if (!debug_flag) {
Damien Miller5428f641999-11-25 11:54:57 +1100674 /*
675 * Record our pid in /etc/sshd_pid to make it easier
676 * to kill the correct sshd. We don\'t want to do
677 * this before the bind above because the bind will
678 * fail if there already is a daemon, and this will
679 * overwrite any old pid in the file.
680 */
Damien Miller95def091999-11-25 00:26:21 +1100681 f = fopen(SSH_DAEMON_PID_FILE, "w");
682 if (f) {
683 fprintf(f, "%u\n", (unsigned int) getpid());
684 fclose(f);
685 }
686 }
687
688 log("Server listening on port %d.", options.port);
689 if (listen(listen_sock, 5) < 0)
690 fatal("listen: %.100s", strerror(errno));
691
692 public_key = RSA_new();
693 sensitive_data.private_key = RSA_new();
694
695 log("Generating %d bit RSA key.", options.server_key_bits);
696 rsa_generate_key(sensitive_data.private_key, public_key,
697 options.server_key_bits);
698 arc4random_stir();
699 log("RSA key generation complete.");
700
701 /* Schedule server key regeneration alarm. */
702 signal(SIGALRM, key_regeneration_alarm);
703 alarm(options.key_regeneration_time);
704
705 /* Arrange to restart on SIGHUP. The handler needs listen_sock. */
706 signal(SIGHUP, sighup_handler);
707 signal(SIGTERM, sigterm_handler);
708 signal(SIGQUIT, sigterm_handler);
709
710 /* Arrange SIGCHLD to be caught. */
711 signal(SIGCHLD, main_sigchld_handler);
712
Damien Miller5428f641999-11-25 11:54:57 +1100713 /*
714 * Stay listening for connections until the system crashes or
715 * the daemon is killed with a signal.
716 */
Damien Miller95def091999-11-25 00:26:21 +1100717 for (;;) {
718 if (received_sighup)
719 sighup_restart();
Damien Miller50945fa1999-12-09 10:31:37 +1100720 /* Wait in poll until there is a connection. */
721 memset(&fds, 0, sizeof(fds));
722 fds.fd = listen_sock;
723 fds.events = POLLIN;
724 if (poll(&fds, 1, -1) == -1) {
725 if (errno == EINTR)
726 continue;
727 fatal("poll: %.100s", strerror(errno));
728 /*NOTREACHED*/
729 }
730 if (fds.revents == 0)
731 continue;
Damien Miller95def091999-11-25 00:26:21 +1100732 aux = sizeof(sin);
733 newsock = accept(listen_sock, (struct sockaddr *) & sin, &aux);
734 if (received_sighup)
735 sighup_restart();
736 if (newsock < 0) {
737 if (errno == EINTR)
738 continue;
739 error("accept: %.100s", strerror(errno));
740 continue;
741 }
Damien Miller5428f641999-11-25 11:54:57 +1100742 /*
743 * Got connection. Fork a child to handle it, unless
744 * we are in debugging mode.
745 */
Damien Miller95def091999-11-25 00:26:21 +1100746 if (debug_flag) {
Damien Miller5428f641999-11-25 11:54:57 +1100747 /*
748 * In debugging mode. Close the listening
749 * socket, and start processing the
750 * connection without forking.
751 */
Damien Miller95def091999-11-25 00:26:21 +1100752 debug("Server will not fork when running in debugging mode.");
753 close(listen_sock);
754 sock_in = newsock;
755 sock_out = newsock;
756 pid = getpid();
757 break;
758 } else {
Damien Miller5428f641999-11-25 11:54:57 +1100759 /*
760 * Normal production daemon. Fork, and have
761 * the child process the connection. The
762 * parent continues listening.
763 */
Damien Miller95def091999-11-25 00:26:21 +1100764 if ((pid = fork()) == 0) {
Damien Miller5428f641999-11-25 11:54:57 +1100765 /*
766 * Child. Close the listening socket, and start using the
767 * accepted socket. Reinitialize logging (since our pid has
768 * changed). We break out of the loop to handle the connection.
769 */
Damien Miller95def091999-11-25 00:26:21 +1100770 close(listen_sock);
771 sock_in = newsock;
772 sock_out = newsock;
773 log_init(av0, options.log_level, options.log_facility, log_stderr);
774 break;
775 }
776 }
777
778 /* Parent. Stay in the loop. */
779 if (pid < 0)
780 error("fork: %.100s", strerror(errno));
781 else
782 debug("Forked child %d.", pid);
783
784 /* Mark that the key has been used (it was "given" to the child). */
785 key_used = 1;
786
787 arc4random_stir();
788
789 /* Close the new socket (the child is now taking care of it). */
790 close(newsock);
791 }
792 }
793
794 /* This is the child processing a new connection. */
795
Damien Miller5428f641999-11-25 11:54:57 +1100796 /*
797 * Disable the key regeneration alarm. We will not regenerate the
798 * key since we are no longer in a position to give it to anyone. We
799 * will not restart on SIGHUP since it no longer makes sense.
800 */
Damien Miller95def091999-11-25 00:26:21 +1100801 alarm(0);
802 signal(SIGALRM, SIG_DFL);
803 signal(SIGHUP, SIG_DFL);
804 signal(SIGTERM, SIG_DFL);
805 signal(SIGQUIT, SIG_DFL);
806 signal(SIGCHLD, SIG_DFL);
807
Damien Miller5428f641999-11-25 11:54:57 +1100808 /*
809 * Set socket options for the connection. We want the socket to
810 * close as fast as possible without waiting for anything. If the
811 * connection is not a socket, these will do nothing.
812 */
813 /* setsockopt(sock_in, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */
Damien Miller95def091999-11-25 00:26:21 +1100814 linger.l_onoff = 1;
815 linger.l_linger = 5;
816 setsockopt(sock_in, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));
817
Damien Miller5428f641999-11-25 11:54:57 +1100818 /*
819 * Register our connection. This turns encryption off because we do
820 * not have a key.
821 */
Damien Miller95def091999-11-25 00:26:21 +1100822 packet_set_connection(sock_in, sock_out);
823
824 remote_port = get_remote_port();
825 remote_ip = get_remote_ipaddr();
826
827 /* Check whether logins are denied from this host. */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000828#ifdef LIBWRAP
Damien Miller95def091999-11-25 00:26:21 +1100829 {
830 struct request_info req;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000831
Damien Miller95def091999-11-25 00:26:21 +1100832 request_init(&req, RQ_DAEMON, av0, RQ_FILE, sock_in, NULL);
833 fromhost(&req);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000834
Damien Miller95def091999-11-25 00:26:21 +1100835 if (!hosts_access(&req)) {
836 close(sock_in);
837 close(sock_out);
838 refuse(&req);
839 }
840 verbose("Connection from %.500s port %d", eval_client(&req), remote_port);
841 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000842#else
Damien Miller95def091999-11-25 00:26:21 +1100843 /* Log the connection. */
844 verbose("Connection from %.500s port %d", remote_ip, remote_port);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000845#endif /* LIBWRAP */
846
Damien Miller5428f641999-11-25 11:54:57 +1100847 /*
848 * We don\'t want to listen forever unless the other side
849 * successfully authenticates itself. So we set up an alarm which is
850 * cleared after successful authentication. A limit of zero
851 * indicates no limit. Note that we don\'t set the alarm in debugging
852 * mode; it is just annoying to have the server exit just when you
853 * are about to discover the bug.
854 */
Damien Miller95def091999-11-25 00:26:21 +1100855 signal(SIGALRM, grace_alarm_handler);
856 if (!debug_flag)
857 alarm(options.login_grace_time);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000858
Damien Miller95def091999-11-25 00:26:21 +1100859 if (client_version_string != NULL) {
860 /* we are exec'ed by sshd2, so skip exchange of protocol version */
861 strlcpy(buf, client_version_string, sizeof(buf));
862 } else {
863 /* Send our protocol version identification. */
864 snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
865 PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION);
Damien Miller037a0dc1999-12-07 15:38:31 +1100866 if (atomicio(write, sock_out, buf, strlen(buf)) != strlen(buf))
Damien Miller95def091999-11-25 00:26:21 +1100867 fatal("Could not write ident string to %s.", get_remote_ipaddr());
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000868
Damien Miller95def091999-11-25 00:26:21 +1100869 /* Read other side\'s version identification. */
870 for (i = 0; i < sizeof(buf) - 1; i++) {
871 if (read(sock_in, &buf[i], 1) != 1)
872 fatal("Did not receive ident string from %s.", get_remote_ipaddr());
873 if (buf[i] == '\r') {
874 buf[i] = '\n';
875 buf[i + 1] = 0;
876 break;
877 }
878 if (buf[i] == '\n') {
879 /* buf[i] == '\n' */
880 buf[i + 1] = 0;
881 break;
882 }
883 }
884 buf[sizeof(buf) - 1] = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000885 }
Damien Miller95def091999-11-25 00:26:21 +1100886
Damien Miller5428f641999-11-25 11:54:57 +1100887 /*
888 * Check that the versions match. In future this might accept
889 * several versions and set appropriate flags to handle them.
890 */
Damien Miller95def091999-11-25 00:26:21 +1100891 if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor,
Damien Miller037a0dc1999-12-07 15:38:31 +1100892 remote_version) != 3) {
893 char *s = "Protocol mismatch.\n";
894
895 (void) atomicio(write, sock_out, s, strlen(s));
Damien Miller95def091999-11-25 00:26:21 +1100896 close(sock_in);
897 close(sock_out);
898 fatal("Bad protocol version identification '%.100s' from %s",
899 buf, get_remote_ipaddr());
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000900 }
Damien Miller95def091999-11-25 00:26:21 +1100901 debug("Client protocol version %d.%d; client software version %.100s",
902 remote_major, remote_minor, remote_version);
903 if (remote_major != PROTOCOL_MAJOR) {
Damien Miller037a0dc1999-12-07 15:38:31 +1100904 char *s = "Protocol major versions differ.\n";
905
906 (void) atomicio(write, sock_out, s, strlen(s));
Damien Miller95def091999-11-25 00:26:21 +1100907 close(sock_in);
908 close(sock_out);
909 fatal("Protocol major versions differ for %s: %d vs. %d",
910 get_remote_ipaddr(),
911 PROTOCOL_MAJOR, remote_major);
912 }
913 /* Check that the client has sufficiently high software version. */
914 if (remote_major == 1 && remote_minor < 3)
915 packet_disconnect("Your ssh version is too old and is no longer supported. Please install a newer version.");
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000916
Damien Miller95def091999-11-25 00:26:21 +1100917 if (remote_major == 1 && remote_minor == 3) {
918 enable_compat13();
919 if (strcmp(remote_version, "OpenSSH-1.1") != 0) {
920 debug("Agent forwarding disabled, remote version is not compatible.");
921 no_agent_forwarding_flag = 1;
922 }
923 }
Damien Miller5428f641999-11-25 11:54:57 +1100924 /*
925 * Check that the connection comes from a privileged port. Rhosts-
926 * and Rhosts-RSA-Authentication only make sense from priviledged
927 * programs. Of course, if the intruder has root access on his local
928 * machine, he can connect from any port. So do not use these
929 * authentication methods from machines that you do not trust.
930 */
Damien Miller95def091999-11-25 00:26:21 +1100931 if (remote_port >= IPPORT_RESERVED ||
932 remote_port < IPPORT_RESERVED / 2) {
933 options.rhosts_authentication = 0;
934 options.rhosts_rsa_authentication = 0;
935 }
936 packet_set_nonblocking();
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000937
Damien Miller95def091999-11-25 00:26:21 +1100938 /* Handle the connection. */
939 do_connection();
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000940
941#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +1100942 /* Cleanup user's ticket cache file. */
943 if (options.kerberos_ticket_cleanup)
944 (void) dest_tkt();
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000945#endif /* KRB4 */
946
Damien Miller95def091999-11-25 00:26:21 +1100947 /* Cleanup user's local Xauthority file. */
948 if (xauthfile)
949 unlink(xauthfile);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000950
Damien Miller95def091999-11-25 00:26:21 +1100951 /* The connection has been terminated. */
952 verbose("Closing connection to %.100s", remote_ip);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000953
Damien Miller06230761999-10-28 14:03:14 +1000954#ifdef HAVE_LIBPAM
Damien Miller95def091999-11-25 00:26:21 +1100955 {
956 int retval;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000957
Damien Miller95def091999-11-25 00:26:21 +1100958 if (pamh != NULL) {
959 debug("Closing PAM session.");
960 retval = pam_close_session((pam_handle_t *)pamh, 0);
961
962 debug("Terminating PAM library.");
963 if (pam_end((pam_handle_t *)pamh, retval) != PAM_SUCCESS)
964 log("Cannot release PAM authentication.");
965
966 fatal_remove_cleanup(&pam_cleanup_proc, NULL);
967 }
968 }
Damien Miller06230761999-10-28 14:03:14 +1000969#endif /* HAVE_LIBPAM */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000970
Damien Miller95def091999-11-25 00:26:21 +1100971 packet_close();
972 exit(0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000973}
974
Damien Miller95def091999-11-25 00:26:21 +1100975/*
976 * Process an incoming connection. Protocol version identifiers have already
977 * been exchanged. This sends server key and performs the key exchange.
978 * Server and host keys will no longer be needed after this functions.
979 */
Damien Miller2ccf6611999-11-15 15:25:10 +1100980void
981do_connection()
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000982{
Damien Miller95def091999-11-25 00:26:21 +1100983 int i, len;
984 BIGNUM *session_key_int;
985 unsigned char session_key[SSH_SESSION_KEY_LENGTH];
986 unsigned char check_bytes[8];
987 char *user;
988 unsigned int cipher_type, auth_mask, protocol_flags;
Damien Millera34a28b1999-12-14 10:47:15 +1100989 int plen, slen, ulen;
Damien Miller95def091999-11-25 00:26:21 +1100990 u_int32_t rand = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000991
Damien Miller5428f641999-11-25 11:54:57 +1100992 /*
993 * Generate check bytes that the client must send back in the user
994 * packet in order for it to be accepted; this is used to defy ip
995 * spoofing attacks. Note that this only works against somebody
996 * doing IP spoofing from a remote machine; any machine on the local
997 * network can still see outgoing packets and catch the random
998 * cookie. This only affects rhosts authentication, and this is one
999 * of the reasons why it is inherently insecure.
1000 */
Damien Miller95def091999-11-25 00:26:21 +11001001 for (i = 0; i < 8; i++) {
1002 if (i % 4 == 0)
1003 rand = arc4random();
1004 check_bytes[i] = rand & 0xff;
1005 rand >>= 8;
1006 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001007
Damien Miller5428f641999-11-25 11:54:57 +11001008 /*
1009 * Send our public key. We include in the packet 64 bits of random
1010 * data that must be matched in the reply in order to prevent IP
1011 * spoofing.
1012 */
Damien Miller95def091999-11-25 00:26:21 +11001013 packet_start(SSH_SMSG_PUBLIC_KEY);
1014 for (i = 0; i < 8; i++)
1015 packet_put_char(check_bytes[i]);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001016
Damien Miller95def091999-11-25 00:26:21 +11001017 /* Store our public server RSA key. */
1018 packet_put_int(BN_num_bits(public_key->n));
1019 packet_put_bignum(public_key->e);
1020 packet_put_bignum(public_key->n);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001021
Damien Miller95def091999-11-25 00:26:21 +11001022 /* Store our public host RSA key. */
1023 packet_put_int(BN_num_bits(sensitive_data.host_key->n));
1024 packet_put_bignum(sensitive_data.host_key->e);
1025 packet_put_bignum(sensitive_data.host_key->n);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001026
Damien Miller95def091999-11-25 00:26:21 +11001027 /* Put protocol flags. */
1028 packet_put_int(SSH_PROTOFLAG_HOST_IN_FWD_OPEN);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001029
Damien Miller95def091999-11-25 00:26:21 +11001030 /* Declare which ciphers we support. */
1031 packet_put_int(cipher_mask());
1032
1033 /* Declare supported authentication types. */
1034 auth_mask = 0;
1035 if (options.rhosts_authentication)
1036 auth_mask |= 1 << SSH_AUTH_RHOSTS;
1037 if (options.rhosts_rsa_authentication)
1038 auth_mask |= 1 << SSH_AUTH_RHOSTS_RSA;
1039 if (options.rsa_authentication)
1040 auth_mask |= 1 << SSH_AUTH_RSA;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001041#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +11001042 if (options.kerberos_authentication)
1043 auth_mask |= 1 << SSH_AUTH_KERBEROS;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001044#endif
1045#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +11001046 if (options.kerberos_tgt_passing)
1047 auth_mask |= 1 << SSH_PASS_KERBEROS_TGT;
1048 if (options.afs_token_passing)
1049 auth_mask |= 1 << SSH_PASS_AFS_TOKEN;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001050#endif
Damien Miller95def091999-11-25 00:26:21 +11001051#ifdef SKEY
1052 if (options.skey_authentication == 1)
1053 auth_mask |= 1 << SSH_AUTH_TIS;
1054#endif
1055 if (options.password_authentication)
1056 auth_mask |= 1 << SSH_AUTH_PASSWORD;
1057 packet_put_int(auth_mask);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001058
Damien Miller95def091999-11-25 00:26:21 +11001059 /* Send the packet and wait for it to be sent. */
1060 packet_send();
1061 packet_write_wait();
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001062
Damien Miller95def091999-11-25 00:26:21 +11001063 debug("Sent %d bit public key and %d bit host key.",
1064 BN_num_bits(public_key->n), BN_num_bits(sensitive_data.host_key->n));
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001065
Damien Miller95def091999-11-25 00:26:21 +11001066 /* Read clients reply (cipher type and session key). */
1067 packet_read_expect(&plen, SSH_CMSG_SESSION_KEY);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001068
Damien Miller50945fa1999-12-09 10:31:37 +11001069 /* Get cipher type and check whether we accept this. */
Damien Miller95def091999-11-25 00:26:21 +11001070 cipher_type = packet_get_char();
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001071
Damien Miller50945fa1999-12-09 10:31:37 +11001072 if (!(cipher_mask() & (1 << cipher_type)))
1073 packet_disconnect("Warning: client selects unsupported cipher.");
1074
Damien Miller95def091999-11-25 00:26:21 +11001075 /* Get check bytes from the packet. These must match those we
1076 sent earlier with the public key packet. */
1077 for (i = 0; i < 8; i++)
1078 if (check_bytes[i] != packet_get_char())
1079 packet_disconnect("IP Spoofing check bytes do not match.");
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001080
Damien Miller95def091999-11-25 00:26:21 +11001081 debug("Encryption type: %.200s", cipher_name(cipher_type));
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001082
Damien Miller95def091999-11-25 00:26:21 +11001083 /* Get the encrypted integer. */
1084 session_key_int = BN_new();
1085 packet_get_bignum(session_key_int, &slen);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001086
Damien Miller95def091999-11-25 00:26:21 +11001087 protocol_flags = packet_get_int();
1088 packet_set_protocol_flags(protocol_flags);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001089
Damien Miller95def091999-11-25 00:26:21 +11001090 packet_integrity_check(plen, 1 + 8 + slen + 4, SSH_CMSG_SESSION_KEY);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001091
Damien Miller5428f641999-11-25 11:54:57 +11001092 /*
1093 * Decrypt it using our private server key and private host key (key
1094 * with larger modulus first).
1095 */
Damien Miller95def091999-11-25 00:26:21 +11001096 if (BN_cmp(sensitive_data.private_key->n, sensitive_data.host_key->n) > 0) {
1097 /* Private key has bigger modulus. */
1098 if (BN_num_bits(sensitive_data.private_key->n) <
1099 BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) {
1100 fatal("do_connection: %s: private_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d",
1101 get_remote_ipaddr(),
1102 BN_num_bits(sensitive_data.private_key->n),
1103 BN_num_bits(sensitive_data.host_key->n),
1104 SSH_KEY_BITS_RESERVED);
1105 }
1106 rsa_private_decrypt(session_key_int, session_key_int,
1107 sensitive_data.private_key);
1108 rsa_private_decrypt(session_key_int, session_key_int,
1109 sensitive_data.host_key);
1110 } else {
1111 /* Host key has bigger modulus (or they are equal). */
1112 if (BN_num_bits(sensitive_data.host_key->n) <
1113 BN_num_bits(sensitive_data.private_key->n) + SSH_KEY_BITS_RESERVED) {
1114 fatal("do_connection: %s: host_key %d < private_key %d + SSH_KEY_BITS_RESERVED %d",
1115 get_remote_ipaddr(),
1116 BN_num_bits(sensitive_data.host_key->n),
1117 BN_num_bits(sensitive_data.private_key->n),
1118 SSH_KEY_BITS_RESERVED);
1119 }
1120 rsa_private_decrypt(session_key_int, session_key_int,
1121 sensitive_data.host_key);
1122 rsa_private_decrypt(session_key_int, session_key_int,
1123 sensitive_data.private_key);
1124 }
Damien Miller356a0b01999-11-08 15:30:59 +11001125
Damien Miller95def091999-11-25 00:26:21 +11001126 compute_session_id(session_id, check_bytes,
1127 sensitive_data.host_key->n,
1128 sensitive_data.private_key->n);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001129
Damien Miller5428f641999-11-25 11:54:57 +11001130 /*
1131 * Extract session key from the decrypted integer. The key is in the
1132 * least significant 256 bits of the integer; the first byte of the
1133 * key is in the highest bits.
1134 */
Damien Miller95def091999-11-25 00:26:21 +11001135 BN_mask_bits(session_key_int, sizeof(session_key) * 8);
1136 len = BN_num_bytes(session_key_int);
1137 if (len < 0 || len > sizeof(session_key))
1138 fatal("do_connection: bad len from %s: session_key_int %d > sizeof(session_key) %d",
1139 get_remote_ipaddr(),
1140 len, sizeof(session_key));
1141 memset(session_key, 0, sizeof(session_key));
1142 BN_bn2bin(session_key_int, session_key + sizeof(session_key) - len);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001143
Damien Miller95def091999-11-25 00:26:21 +11001144 /* Xor the first 16 bytes of the session key with the session id. */
1145 for (i = 0; i < 16; i++)
1146 session_key[i] ^= session_id[i];
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001147
Damien Miller95def091999-11-25 00:26:21 +11001148 /* Destroy the decrypted integer. It is no longer needed. */
1149 BN_clear_free(session_key_int);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001150
Damien Miller95def091999-11-25 00:26:21 +11001151 /* Set the session key. From this on all communications will be encrypted. */
1152 packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, cipher_type);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001153
Damien Miller95def091999-11-25 00:26:21 +11001154 /* Destroy our copy of the session key. It is no longer needed. */
1155 memset(session_key, 0, sizeof(session_key));
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001156
Damien Miller95def091999-11-25 00:26:21 +11001157 debug("Received session key; encryption turned on.");
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001158
Damien Miller95def091999-11-25 00:26:21 +11001159 /* Send an acknowledgement packet. Note that this packet is sent encrypted. */
1160 packet_start(SSH_SMSG_SUCCESS);
1161 packet_send();
1162 packet_write_wait();
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001163
Damien Miller95def091999-11-25 00:26:21 +11001164 /* Get the name of the user that we wish to log in as. */
1165 packet_read_expect(&plen, SSH_CMSG_USER);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001166
Damien Miller95def091999-11-25 00:26:21 +11001167 /* Get the user name. */
Damien Millera34a28b1999-12-14 10:47:15 +11001168 user = packet_get_string(&ulen);
1169 packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
Damien Miller95def091999-11-25 00:26:21 +11001170
1171 /* Destroy the private and public keys. They will no longer be needed. */
1172 RSA_free(public_key);
1173 RSA_free(sensitive_data.private_key);
1174 RSA_free(sensitive_data.host_key);
1175
1176 setproctitle("%s", user);
1177 /* Do the authentication. */
1178 do_authentication(user);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001179}
1180
Damien Miller95def091999-11-25 00:26:21 +11001181/*
1182 * Check if the user is allowed to log in via ssh. If user is listed in
1183 * DenyUsers or user's primary group is listed in DenyGroups, false will
1184 * be returned. If AllowUsers isn't empty and user isn't listed there, or
1185 * if AllowGroups isn't empty and user isn't listed there, false will be
1186 * returned. Otherwise true is returned.
1187 * XXX This function should also check if user has a valid shell
1188 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001189static int
Damien Miller95def091999-11-25 00:26:21 +11001190allowed_user(struct passwd * pw)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001191{
Damien Miller95def091999-11-25 00:26:21 +11001192 struct group *grp;
1193 int i;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001194
Damien Miller95def091999-11-25 00:26:21 +11001195 /* Shouldn't be called if pw is NULL, but better safe than sorry... */
1196 if (!pw)
1197 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001198
Damien Miller95def091999-11-25 00:26:21 +11001199 /* XXX Should check for valid login shell */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001200
Damien Miller95def091999-11-25 00:26:21 +11001201 /* Return false if user is listed in DenyUsers */
1202 if (options.num_deny_users > 0) {
1203 if (!pw->pw_name)
1204 return 0;
1205 for (i = 0; i < options.num_deny_users; i++)
1206 if (match_pattern(pw->pw_name, options.deny_users[i]))
1207 return 0;
1208 }
Damien Miller5428f641999-11-25 11:54:57 +11001209 /* Return false if AllowUsers isn't empty and user isn't listed there */
Damien Miller95def091999-11-25 00:26:21 +11001210 if (options.num_allow_users > 0) {
1211 if (!pw->pw_name)
1212 return 0;
1213 for (i = 0; i < options.num_allow_users; i++)
1214 if (match_pattern(pw->pw_name, options.allow_users[i]))
1215 break;
1216 /* i < options.num_allow_users iff we break for loop */
1217 if (i >= options.num_allow_users)
1218 return 0;
1219 }
1220 /* Get the primary group name if we need it. Return false if it fails */
1221 if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
1222 grp = getgrgid(pw->pw_gid);
1223 if (!grp)
1224 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001225
Damien Miller95def091999-11-25 00:26:21 +11001226 /* Return false if user's group is listed in DenyGroups */
1227 if (options.num_deny_groups > 0) {
1228 if (!grp->gr_name)
1229 return 0;
1230 for (i = 0; i < options.num_deny_groups; i++)
1231 if (match_pattern(grp->gr_name, options.deny_groups[i]))
1232 return 0;
1233 }
Damien Miller5428f641999-11-25 11:54:57 +11001234 /*
1235 * Return false if AllowGroups isn't empty and user's group
1236 * isn't listed there
1237 */
Damien Miller95def091999-11-25 00:26:21 +11001238 if (options.num_allow_groups > 0) {
1239 if (!grp->gr_name)
1240 return 0;
1241 for (i = 0; i < options.num_allow_groups; i++)
1242 if (match_pattern(grp->gr_name, options.allow_groups[i]))
1243 break;
1244 /* i < options.num_allow_groups iff we break for
1245 loop */
1246 if (i >= options.num_allow_groups)
1247 return 0;
1248 }
1249 }
1250 /* We found no reason not to let this user try to log on... */
1251 return 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001252}
1253
Damien Miller95def091999-11-25 00:26:21 +11001254/*
1255 * Performs authentication of an incoming connection. Session key has already
1256 * been exchanged and encryption is enabled. User is the user name to log
1257 * in as (received from the client).
1258 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001259void
Damien Miller2ccf6611999-11-15 15:25:10 +11001260do_authentication(char *user)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001261{
Damien Miller95def091999-11-25 00:26:21 +11001262 struct passwd *pw, pwcopy;
Damien Miller2ccf6611999-11-15 15:25:10 +11001263
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001264#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +11001265 /* If machine has AFS, set process authentication group. */
1266 if (k_hasafs()) {
1267 k_setpag();
1268 k_unlog();
1269 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001270#endif /* AFS */
Damien Miller95def091999-11-25 00:26:21 +11001271
1272 /* Verify that the user is a valid user. */
1273 pw = getpwnam(user);
1274 if (!pw || !allowed_user(pw))
1275 do_fake_authloop(user);
1276
1277 /* Take a copy of the returned structure. */
1278 memset(&pwcopy, 0, sizeof(pwcopy));
1279 pwcopy.pw_name = xstrdup(pw->pw_name);
1280 pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
1281 pwcopy.pw_uid = pw->pw_uid;
1282 pwcopy.pw_gid = pw->pw_gid;
1283 pwcopy.pw_dir = xstrdup(pw->pw_dir);
1284 pwcopy.pw_shell = xstrdup(pw->pw_shell);
1285 pw = &pwcopy;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001286
Damien Miller06230761999-10-28 14:03:14 +10001287#ifdef HAVE_LIBPAM
Damien Miller95def091999-11-25 00:26:21 +11001288 {
1289 int pam_retval;
Damien Miller2ccf6611999-11-15 15:25:10 +11001290
Damien Miller95def091999-11-25 00:26:21 +11001291 debug("Starting up PAM with username \"%.200s\"", pw->pw_name);
Damien Miller2ccf6611999-11-15 15:25:10 +11001292
Damien Miller95def091999-11-25 00:26:21 +11001293 pam_retval = pam_start("sshd", pw->pw_name, &conv, (pam_handle_t**)&pamh);
1294 if (pam_retval != PAM_SUCCESS)
1295 fatal("PAM initialisation failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
1296
1297 fatal_add_cleanup(&pam_cleanup_proc, NULL);
1298 }
Damien Miller06230761999-10-28 14:03:14 +10001299#endif
Damien Miller3d112ef1999-10-28 13:20:30 +10001300
Damien Miller5428f641999-11-25 11:54:57 +11001301 /*
1302 * If we are not running as root, the user must have the same uid as
1303 * the server.
1304 */
Damien Miller95def091999-11-25 00:26:21 +11001305 if (getuid() != 0 && pw->pw_uid != getuid())
1306 packet_disconnect("Cannot change user when server not running as root.");
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001307
Damien Miller95def091999-11-25 00:26:21 +11001308 debug("Attempting authentication for %.100s.", user);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001309
Damien Miller95def091999-11-25 00:26:21 +11001310 /* If the user has no password, accept authentication immediately. */
1311 if (options.password_authentication &&
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001312#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +11001313 (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001314#endif /* KRB4 */
Damien Miller2e1b0821999-12-25 10:11:29 +11001315#ifdef HAVE_LIBPAM
1316 do_pam_auth(pw->pw_name, "")) {
1317#else /* HAVE_LIBPAM */
Damien Miller95def091999-11-25 00:26:21 +11001318 auth_password(pw, "")) {
Damien Miller2e1b0821999-12-25 10:11:29 +11001319#endif /* HAVE_LIBPAM */
Damien Miller95def091999-11-25 00:26:21 +11001320 /* Authentication with empty password succeeded. */
1321 log("Login for user %s from %.100s, accepted without authentication.",
1322 pw->pw_name, get_remote_ipaddr());
1323 } else {
1324 /* Loop until the user has been authenticated or the
1325 connection is closed, do_authloop() returns only if
1326 authentication is successfull */
1327 do_authloop(pw);
1328 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001329
Damien Miller95def091999-11-25 00:26:21 +11001330 /* Check if the user is logging in as root and root logins are disallowed. */
1331 if (pw->pw_uid == 0 && !options.permit_root_login) {
1332 if (forced_command)
1333 log("Root login accepted for forced command.");
1334 else
1335 packet_disconnect("ROOT LOGIN REFUSED FROM %.200s",
1336 get_canonical_hostname());
1337 }
1338 /* The user has been authenticated and accepted. */
1339 packet_start(SSH_SMSG_SUCCESS);
1340 packet_send();
1341 packet_write_wait();
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001342
Damien Miller95def091999-11-25 00:26:21 +11001343 /* Perform session preparation. */
1344 do_authenticated(pw);
Damien Miller2ccf6611999-11-15 15:25:10 +11001345}
1346
Damien Miller95def091999-11-25 00:26:21 +11001347#define AUTH_FAIL_MAX 6
1348#define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)
1349#define AUTH_FAIL_MSG "Too many authentication failures for %.100s"
Damien Miller2ccf6611999-11-15 15:25:10 +11001350
Damien Miller95def091999-11-25 00:26:21 +11001351/*
1352 * read packets and try to authenticate local user *pw.
1353 * return if authentication is successfull
1354 */
Damien Miller2ccf6611999-11-15 15:25:10 +11001355void
Damien Miller95def091999-11-25 00:26:21 +11001356do_authloop(struct passwd * pw)
Damien Miller2ccf6611999-11-15 15:25:10 +11001357{
Damien Miller95def091999-11-25 00:26:21 +11001358 int attempt = 0;
1359 unsigned int bits;
1360 BIGNUM *client_host_key_e, *client_host_key_n;
1361 BIGNUM *n;
1362 char *client_user = NULL, *password = NULL;
1363 char user[1024];
1364 int plen, dlen, nlen, ulen, elen;
1365 int type = 0;
1366 void (*authlog) (const char *fmt,...) = verbose;
Damien Miller2ccf6611999-11-15 15:25:10 +11001367
Damien Miller95def091999-11-25 00:26:21 +11001368 /* Indicate that authentication is needed. */
1369 packet_start(SSH_SMSG_FAILURE);
1370 packet_send();
1371 packet_write_wait();
Damien Miller2ccf6611999-11-15 15:25:10 +11001372
Damien Miller95def091999-11-25 00:26:21 +11001373 for (attempt = 1;; attempt++) {
1374 int authenticated = 0;
1375 strlcpy(user, "", sizeof user);
Damien Miller2ccf6611999-11-15 15:25:10 +11001376
Damien Miller95def091999-11-25 00:26:21 +11001377 /* Get a packet from the client. */
1378 type = packet_read(&plen);
1379
1380 /* Process the packet. */
1381 switch (type) {
Damien Miller2ccf6611999-11-15 15:25:10 +11001382#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +11001383 case SSH_CMSG_HAVE_KERBEROS_TGT:
1384 if (!options.kerberos_tgt_passing) {
1385 /* packet_get_all(); */
1386 verbose("Kerberos tgt passing disabled.");
1387 break;
1388 } else {
1389 /* Accept Kerberos tgt. */
1390 char *tgt = packet_get_string(&dlen);
1391 packet_integrity_check(plen, 4 + dlen, type);
1392 if (!auth_kerberos_tgt(pw, tgt))
1393 verbose("Kerberos tgt REFUSED for %s", pw->pw_name);
1394 xfree(tgt);
1395 }
1396 continue;
1397
1398 case SSH_CMSG_HAVE_AFS_TOKEN:
1399 if (!options.afs_token_passing || !k_hasafs()) {
1400 /* packet_get_all(); */
1401 verbose("AFS token passing disabled.");
1402 break;
1403 } else {
1404 /* Accept AFS token. */
1405 char *token_string = packet_get_string(&dlen);
1406 packet_integrity_check(plen, 4 + dlen, type);
1407 if (!auth_afs_token(pw, token_string))
1408 verbose("AFS token REFUSED for %s", pw->pw_name);
1409 xfree(token_string);
1410 }
1411 continue;
Damien Miller2ccf6611999-11-15 15:25:10 +11001412#endif /* AFS */
Damien Miller2ccf6611999-11-15 15:25:10 +11001413#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +11001414 case SSH_CMSG_AUTH_KERBEROS:
1415 if (!options.kerberos_authentication) {
1416 /* packet_get_all(); */
1417 verbose("Kerberos authentication disabled.");
1418 break;
1419 } else {
1420 /* Try Kerberos v4 authentication. */
1421 KTEXT_ST auth;
1422 char *tkt_user = NULL;
1423 char *kdata = packet_get_string((unsigned int *) &auth.length);
1424 packet_integrity_check(plen, 4 + auth.length, type);
Damien Miller2ccf6611999-11-15 15:25:10 +11001425
Damien Miller95def091999-11-25 00:26:21 +11001426 if (auth.length < MAX_KTXT_LEN)
1427 memcpy(auth.dat, kdata, auth.length);
1428 xfree(kdata);
1429
1430 authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user);
1431
1432 if (authenticated) {
1433 snprintf(user, sizeof user, " tktuser %s", tkt_user);
1434 xfree(tkt_user);
1435 }
1436 }
1437 break;
Damien Miller2ccf6611999-11-15 15:25:10 +11001438#endif /* KRB4 */
Damien Miller2ccf6611999-11-15 15:25:10 +11001439
Damien Miller95def091999-11-25 00:26:21 +11001440 case SSH_CMSG_AUTH_RHOSTS:
1441 if (!options.rhosts_authentication) {
1442 verbose("Rhosts authentication disabled.");
1443 break;
1444 }
Damien Miller5428f641999-11-25 11:54:57 +11001445 /*
1446 * Get client user name. Note that we just have to
1447 * trust the client; this is one reason why rhosts
1448 * authentication is insecure. (Another is
1449 * IP-spoofing on a local network.)
1450 */
Damien Miller95def091999-11-25 00:26:21 +11001451 client_user = packet_get_string(&ulen);
1452 packet_integrity_check(plen, 4 + ulen, type);
1453
1454 /* Try to authenticate using /etc/hosts.equiv and
1455 .rhosts. */
1456 authenticated = auth_rhosts(pw, client_user);
1457
1458 snprintf(user, sizeof user, " ruser %s", client_user);
Damien Miller2ccf6611999-11-15 15:25:10 +11001459#ifndef HAVE_LIBPAM
Damien Miller95def091999-11-25 00:26:21 +11001460 xfree(client_user);
Damien Miller2ccf6611999-11-15 15:25:10 +11001461#endif /* HAVE_LIBPAM */
Damien Miller95def091999-11-25 00:26:21 +11001462 break;
Damien Miller7e8e8201999-11-16 13:37:16 +11001463
Damien Miller95def091999-11-25 00:26:21 +11001464 case SSH_CMSG_AUTH_RHOSTS_RSA:
1465 if (!options.rhosts_rsa_authentication) {
1466 verbose("Rhosts with RSA authentication disabled.");
1467 break;
1468 }
Damien Miller5428f641999-11-25 11:54:57 +11001469 /*
1470 * Get client user name. Note that we just have to
1471 * trust the client; root on the client machine can
1472 * claim to be any user.
1473 */
Damien Miller95def091999-11-25 00:26:21 +11001474 client_user = packet_get_string(&ulen);
1475
1476 /* Get the client host key. */
1477 client_host_key_e = BN_new();
1478 client_host_key_n = BN_new();
1479 bits = packet_get_int();
1480 packet_get_bignum(client_host_key_e, &elen);
1481 packet_get_bignum(client_host_key_n, &nlen);
1482
1483 if (bits != BN_num_bits(client_host_key_n))
1484 error("Warning: keysize mismatch for client_host_key: "
1485 "actual %d, announced %d", BN_num_bits(client_host_key_n), bits);
1486 packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type);
1487
1488 authenticated = auth_rhosts_rsa(pw, client_user,
1489 client_host_key_e, client_host_key_n);
1490 BN_clear_free(client_host_key_e);
1491 BN_clear_free(client_host_key_n);
1492
1493 snprintf(user, sizeof user, " ruser %s", client_user);
Damien Miller2ccf6611999-11-15 15:25:10 +11001494#ifndef HAVE_LIBPAM
Damien Miller95def091999-11-25 00:26:21 +11001495 xfree(client_user);
Damien Miller2ccf6611999-11-15 15:25:10 +11001496#endif /* HAVE_LIBPAM */
Damien Miller95def091999-11-25 00:26:21 +11001497 break;
Damien Miller81428f91999-11-18 09:28:11 +11001498
Damien Miller95def091999-11-25 00:26:21 +11001499 case SSH_CMSG_AUTH_RSA:
1500 if (!options.rsa_authentication) {
1501 verbose("RSA authentication disabled.");
1502 break;
1503 }
1504 /* RSA authentication requested. */
1505 n = BN_new();
1506 packet_get_bignum(n, &nlen);
1507 packet_integrity_check(plen, nlen, type);
1508 authenticated = auth_rsa(pw, n);
1509 BN_clear_free(n);
1510 break;
1511
1512 case SSH_CMSG_AUTH_PASSWORD:
1513 if (!options.password_authentication) {
1514 verbose("Password authentication disabled.");
1515 break;
1516 }
Damien Miller5428f641999-11-25 11:54:57 +11001517 /*
1518 * Read user password. It is in plain text, but was
1519 * transmitted over the encrypted channel so it is
1520 * not visible to an outside observer.
1521 */
Damien Miller95def091999-11-25 00:26:21 +11001522 password = packet_get_string(&dlen);
1523 packet_integrity_check(plen, 4 + dlen, type);
1524
Damien Miller06230761999-10-28 14:03:14 +10001525#ifdef HAVE_LIBPAM
Damien Miller95def091999-11-25 00:26:21 +11001526 /* Do PAM auth with password */
Damien Miller2e1b0821999-12-25 10:11:29 +11001527 authenticated = do_pam_auth(pw->pw_name, password);
Damien Miller2ccf6611999-11-15 15:25:10 +11001528#else /* HAVE_LIBPAM */
Damien Miller95def091999-11-25 00:26:21 +11001529 /* Try authentication with the password. */
1530 authenticated = auth_password(pw, password);
Damien Miller2e1b0821999-12-25 10:11:29 +11001531#endif /* HAVE_LIBPAM */
Damien Miller95def091999-11-25 00:26:21 +11001532 memset(password, 0, strlen(password));
1533 xfree(password);
1534 break;
Damien Miller2ccf6611999-11-15 15:25:10 +11001535
Damien Miller95def091999-11-25 00:26:21 +11001536#ifdef SKEY
1537 case SSH_CMSG_AUTH_TIS:
1538 debug("rcvd SSH_CMSG_AUTH_TIS");
1539 if (options.skey_authentication == 1) {
1540 char *skeyinfo = skey_keyinfo(pw->pw_name);
1541 if (skeyinfo == NULL) {
1542 debug("generating fake skeyinfo for %.100s.", pw->pw_name);
1543 skeyinfo = skey_fake_keyinfo(pw->pw_name);
1544 }
1545 if (skeyinfo != NULL) {
Damien Miller5428f641999-11-25 11:54:57 +11001546 /* we send our s/key- in tis-challenge messages */
Damien Miller95def091999-11-25 00:26:21 +11001547 debug("sending challenge '%s'", skeyinfo);
1548 packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
1549 packet_put_string(skeyinfo, strlen(skeyinfo));
1550 packet_send();
1551 packet_write_wait();
1552 continue;
1553 }
1554 }
1555 break;
1556 case SSH_CMSG_AUTH_TIS_RESPONSE:
1557 debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
1558 if (options.skey_authentication == 1) {
1559 char *response = packet_get_string(&dlen);
1560 debug("skey response == '%s'", response);
1561 packet_integrity_check(plen, 4 + dlen, type);
1562 authenticated = (skey_haskey(pw->pw_name) == 0 &&
1563 skey_passcheck(pw->pw_name, response) != -1);
1564 xfree(response);
1565 }
1566 break;
1567#else
1568 case SSH_CMSG_AUTH_TIS:
1569 /* TIS Authentication is unsupported */
1570 log("TIS authentication unsupported.");
1571 break;
1572#endif
1573
1574 default:
Damien Miller5428f641999-11-25 11:54:57 +11001575 /*
1576 * Any unknown messages will be ignored (and failure
1577 * returned) during authentication.
1578 */
Damien Miller95def091999-11-25 00:26:21 +11001579 log("Unknown message during authentication: type %d", type);
1580 break;
1581 }
1582
1583 /* Raise logging level */
1584 if (authenticated ||
1585 attempt == AUTH_FAIL_LOG ||
1586 type == SSH_CMSG_AUTH_PASSWORD)
1587 authlog = log;
1588
1589 authlog("%s %s for %.200s from %.200s port %d%s",
1590 authenticated ? "Accepted" : "Failed",
1591 get_authname(type),
1592 pw->pw_uid == 0 ? "ROOT" : pw->pw_name,
1593 get_remote_ipaddr(),
1594 get_remote_port(),
1595 user);
Damien Miller2ccf6611999-11-15 15:25:10 +11001596
Damien Millereabf3411999-12-07 14:56:27 +11001597#ifndef HAVE_LIBPAM
Damien Miller95def091999-11-25 00:26:21 +11001598 if (authenticated)
1599 return;
1600
1601 if (attempt > AUTH_FAIL_MAX)
1602 packet_disconnect(AUTH_FAIL_MSG, pw->pw_name);
Damien Millereabf3411999-12-07 14:56:27 +11001603#else /* HAVE_LIBPAM */
1604 if (authenticated) {
Damien Millerbf1c9b21999-12-09 10:16:54 +11001605 do_pam_account(pw->pw_name, client_user);
Damien Millereabf3411999-12-07 14:56:27 +11001606
Damien Millereabf3411999-12-07 14:56:27 +11001607 if (client_user != NULL)
1608 xfree(client_user);
1609
Damien Millereabf3411999-12-07 14:56:27 +11001610 return;
1611 }
1612
1613 if (attempt > AUTH_FAIL_MAX) {
Damien Millereabf3411999-12-07 14:56:27 +11001614 if (client_user != NULL)
1615 xfree(client_user);
1616
Damien Millereabf3411999-12-07 14:56:27 +11001617 packet_disconnect(AUTH_FAIL_MSG, pw->pw_name);
1618 }
1619#endif /* HAVE_LIBPAM */
Damien Miller95def091999-11-25 00:26:21 +11001620
1621 /* Send a message indicating that the authentication attempt failed. */
1622 packet_start(SSH_SMSG_FAILURE);
1623 packet_send();
1624 packet_write_wait();
1625 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001626}
1627
Damien Miller95def091999-11-25 00:26:21 +11001628/*
1629 * The user does not exist or access is denied,
1630 * but fake indication that authentication is needed.
1631 */
Damien Miller2ccf6611999-11-15 15:25:10 +11001632void
1633do_fake_authloop(char *user)
Damien Miller3d112ef1999-10-28 13:20:30 +10001634{
Damien Miller95def091999-11-25 00:26:21 +11001635 int attempt = 0;
Damien Miller2ccf6611999-11-15 15:25:10 +11001636
Damien Miller95def091999-11-25 00:26:21 +11001637 log("Faking authloop for illegal user %.200s from %.200s port %d",
1638 user,
1639 get_remote_ipaddr(),
1640 get_remote_port());
Damien Miller3d112ef1999-10-28 13:20:30 +10001641
Damien Miller95def091999-11-25 00:26:21 +11001642 /* Indicate that authentication is needed. */
1643 packet_start(SSH_SMSG_FAILURE);
1644 packet_send();
1645 packet_write_wait();
1646
Damien Miller5428f641999-11-25 11:54:57 +11001647 /*
1648 * Keep reading packets, and always respond with a failure. This is
1649 * to avoid disclosing whether such a user really exists.
1650 */
Damien Miller95def091999-11-25 00:26:21 +11001651 for (attempt = 1;; attempt++) {
Damien Miller5428f641999-11-25 11:54:57 +11001652 /* Read a packet. This will not return if the client disconnects. */
Damien Miller95def091999-11-25 00:26:21 +11001653 int plen;
1654 int type = packet_read(&plen);
Damien Miller2ccf6611999-11-15 15:25:10 +11001655#ifdef SKEY
Damien Miller95def091999-11-25 00:26:21 +11001656 int dlen;
1657 char *password, *skeyinfo;
Damien Millera34a28b1999-12-14 10:47:15 +11001658 /* Try to send a fake s/key challenge. */
1659 if (options.skey_authentication == 1 &&
Damien Miller95def091999-11-25 00:26:21 +11001660 (skeyinfo = skey_fake_keyinfo(user)) != NULL) {
Damien Millera34a28b1999-12-14 10:47:15 +11001661 if (type == SSH_CMSG_AUTH_TIS) {
1662 packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
1663 packet_put_string(skeyinfo, strlen(skeyinfo));
1664 packet_send();
1665 packet_write_wait();
1666 continue;
1667 } else if (type == SSH_CMSG_AUTH_PASSWORD &&
1668 options.password_authentication &&
1669 (password = packet_get_string(&dlen)) != NULL &&
1670 dlen == 5 &&
1671 strncasecmp(password, "s/key", 5) == 0 ) {
1672 packet_send_debug(skeyinfo);
1673 }
Damien Miller95def091999-11-25 00:26:21 +11001674 }
Damien Miller2ccf6611999-11-15 15:25:10 +11001675#endif
Damien Miller95def091999-11-25 00:26:21 +11001676 if (attempt > AUTH_FAIL_MAX)
1677 packet_disconnect(AUTH_FAIL_MSG, user);
1678
Damien Miller5428f641999-11-25 11:54:57 +11001679 /*
1680 * Send failure. This should be indistinguishable from a
1681 * failed authentication.
1682 */
Damien Miller95def091999-11-25 00:26:21 +11001683 packet_start(SSH_SMSG_FAILURE);
1684 packet_send();
1685 packet_write_wait();
1686 }
1687 /* NOTREACHED */
1688 abort();
Damien Miller3d112ef1999-10-28 13:20:30 +10001689}
1690
Damien Miller2ccf6611999-11-15 15:25:10 +11001691
Damien Miller95def091999-11-25 00:26:21 +11001692/*
1693 * Remove local Xauthority file.
1694 */
Damien Miller5ce662a1999-11-11 17:57:39 +11001695static void
1696xauthfile_cleanup_proc(void *ignore)
1697{
Damien Miller95def091999-11-25 00:26:21 +11001698 debug("xauthfile_cleanup_proc called");
Damien Miller5ce662a1999-11-11 17:57:39 +11001699
Damien Miller95def091999-11-25 00:26:21 +11001700 if (xauthfile != NULL) {
1701 unlink(xauthfile);
1702 xfree(xauthfile);
1703 xauthfile = NULL;
1704 }
Damien Miller5ce662a1999-11-11 17:57:39 +11001705}
1706
Damien Miller95def091999-11-25 00:26:21 +11001707/*
1708 * Prepares for an interactive session. This is called after the user has
1709 * been successfully authenticated. During this message exchange, pseudo
1710 * terminals are allocated, X11, TCP/IP, and authentication agent forwardings
1711 * are requested, etc.
1712 */
1713void
1714do_authenticated(struct passwd * pw)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001715{
Damien Miller95def091999-11-25 00:26:21 +11001716 int type;
1717 int compression_level = 0, enable_compression_after_reply = 0;
1718 int have_pty = 0, ptyfd = -1, ttyfd = -1, xauthfd = -1;
1719 int row, col, xpixel, ypixel, screen;
1720 char ttyname[64];
1721 char *command, *term = NULL, *display = NULL, *proto = NULL,
1722 *data = NULL;
1723 struct group *grp;
1724 gid_t tty_gid;
1725 mode_t tty_mode;
1726 int n_bytes;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001727
Damien Miller5428f641999-11-25 11:54:57 +11001728 /*
1729 * Cancel the alarm we set to limit the time taken for
1730 * authentication.
1731 */
Damien Miller95def091999-11-25 00:26:21 +11001732 alarm(0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001733
Damien Miller5428f641999-11-25 11:54:57 +11001734 /*
1735 * Inform the channel mechanism that we are the server side and that
1736 * the client may request to connect to any port at all. (The user
1737 * could do it anyway, and we wouldn\'t know what is permitted except
1738 * by the client telling us, so we can equally well trust the client
1739 * not to request anything bogus.)
1740 */
Damien Miller95def091999-11-25 00:26:21 +11001741 channel_permit_all_opens();
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001742
Damien Miller5428f641999-11-25 11:54:57 +11001743 /*
1744 * We stay in this loop until the client requests to execute a shell
1745 * or a command.
1746 */
Damien Miller95def091999-11-25 00:26:21 +11001747 while (1) {
1748 int plen, dlen;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001749
Damien Miller95def091999-11-25 00:26:21 +11001750 /* Get a packet from the client. */
1751 type = packet_read(&plen);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001752
Damien Miller95def091999-11-25 00:26:21 +11001753 /* Process the packet. */
1754 switch (type) {
1755 case SSH_CMSG_REQUEST_COMPRESSION:
1756 packet_integrity_check(plen, 4, type);
1757 compression_level = packet_get_int();
1758 if (compression_level < 1 || compression_level > 9) {
1759 packet_send_debug("Received illegal compression level %d.",
1760 compression_level);
1761 goto fail;
1762 }
1763 /* Enable compression after we have responded with SUCCESS. */
1764 enable_compression_after_reply = 1;
1765 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001766
Damien Miller95def091999-11-25 00:26:21 +11001767 case SSH_CMSG_REQUEST_PTY:
1768 if (no_pty_flag) {
1769 debug("Allocating a pty not permitted for this authentication.");
1770 goto fail;
1771 }
1772 if (have_pty)
1773 packet_disconnect("Protocol error: you already have a pty.");
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001774
Damien Miller95def091999-11-25 00:26:21 +11001775 debug("Allocating pty.");
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001776
Damien Miller95def091999-11-25 00:26:21 +11001777 /* Allocate a pty and open it. */
Damien Miller037a0dc1999-12-07 15:38:31 +11001778 if (!pty_allocate(&ptyfd, &ttyfd, ttyname,
1779 sizeof(ttyname))) {
Damien Miller95def091999-11-25 00:26:21 +11001780 error("Failed to allocate pty.");
1781 goto fail;
1782 }
1783 /* Determine the group to make the owner of the tty. */
1784 grp = getgrnam("tty");
1785 if (grp) {
1786 tty_gid = grp->gr_gid;
1787 tty_mode = S_IRUSR | S_IWUSR | S_IWGRP;
1788 } else {
1789 tty_gid = pw->pw_gid;
1790 tty_mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
1791 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001792
Damien Miller95def091999-11-25 00:26:21 +11001793 /* Change ownership of the tty. */
1794 if (chown(ttyname, pw->pw_uid, tty_gid) < 0)
1795 fatal("chown(%.100s, %d, %d) failed: %.100s",
1796 ttyname, pw->pw_uid, tty_gid, strerror(errno));
1797 if (chmod(ttyname, tty_mode) < 0)
1798 fatal("chmod(%.100s, 0%o) failed: %.100s",
1799 ttyname, tty_mode, strerror(errno));
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001800
Damien Miller95def091999-11-25 00:26:21 +11001801 /* Get TERM from the packet. Note that the value may be of arbitrary length. */
1802 term = packet_get_string(&dlen);
1803 packet_integrity_check(dlen, strlen(term), type);
1804 /* packet_integrity_check(plen, 4 + dlen + 4*4 + n_bytes, type); */
1805 /* Remaining bytes */
1806 n_bytes = plen - (4 + dlen + 4 * 4);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001807
Damien Miller95def091999-11-25 00:26:21 +11001808 if (strcmp(term, "") == 0)
1809 term = NULL;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001810
Damien Miller95def091999-11-25 00:26:21 +11001811 /* Get window size from the packet. */
1812 row = packet_get_int();
1813 col = packet_get_int();
1814 xpixel = packet_get_int();
1815 ypixel = packet_get_int();
1816 pty_change_window_size(ptyfd, row, col, xpixel, ypixel);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001817
Damien Miller95def091999-11-25 00:26:21 +11001818 /* Get tty modes from the packet. */
1819 tty_parse_modes(ttyfd, &n_bytes);
1820 packet_integrity_check(plen, 4 + dlen + 4 * 4 + n_bytes, type);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001821
Damien Miller95def091999-11-25 00:26:21 +11001822 /* Indicate that we now have a pty. */
1823 have_pty = 1;
Damien Millerbf1c9b21999-12-09 10:16:54 +11001824
1825#ifdef HAVE_LIBPAM
1826 /* do the pam_open_session since we have the pty */
1827 do_pam_session(pw->pw_name,ttyname);
1828#endif /* HAVE_LIBPAM */
1829
Damien Miller95def091999-11-25 00:26:21 +11001830 break;
1831
1832 case SSH_CMSG_X11_REQUEST_FORWARDING:
1833 if (!options.x11_forwarding) {
1834 packet_send_debug("X11 forwarding disabled in server configuration file.");
1835 goto fail;
1836 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001837#ifdef XAUTH_PATH
Damien Miller95def091999-11-25 00:26:21 +11001838 if (no_x11_forwarding_flag) {
1839 packet_send_debug("X11 forwarding not permitted for this authentication.");
1840 goto fail;
1841 }
1842 debug("Received request for X11 forwarding with auth spoofing.");
1843 if (display)
1844 packet_disconnect("Protocol error: X11 display already set.");
1845 {
1846 int proto_len, data_len;
1847 proto = packet_get_string(&proto_len);
1848 data = packet_get_string(&data_len);
1849 packet_integrity_check(plen, 4 + proto_len + 4 + data_len + 4, type);
1850 }
1851 if (packet_get_protocol_flags() & SSH_PROTOFLAG_SCREEN_NUMBER)
1852 screen = packet_get_int();
1853 else
1854 screen = 0;
Damien Millera34a28b1999-12-14 10:47:15 +11001855 display = x11_create_display_inet(screen, options.x11_display_offset);
Damien Miller95def091999-11-25 00:26:21 +11001856 if (!display)
1857 goto fail;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001858
Damien Miller95def091999-11-25 00:26:21 +11001859 /* Setup to always have a local .Xauthority. */
1860 xauthfile = xmalloc(MAXPATHLEN);
1861 snprintf(xauthfile, MAXPATHLEN, "/tmp/XauthXXXXXX");
1862
1863 if ((xauthfd = mkstemp(xauthfile)) != -1) {
1864 fchown(xauthfd, pw->pw_uid, pw->pw_gid);
1865 close(xauthfd);
1866 fatal_add_cleanup(xauthfile_cleanup_proc, NULL);
1867 } else {
1868 xfree(xauthfile);
1869 xauthfile = NULL;
1870 }
1871 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001872#else /* XAUTH_PATH */
Damien Miller95def091999-11-25 00:26:21 +11001873 packet_send_debug("No xauth program; cannot forward with spoofing.");
1874 goto fail;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001875#endif /* XAUTH_PATH */
1876
Damien Miller95def091999-11-25 00:26:21 +11001877 case SSH_CMSG_AGENT_REQUEST_FORWARDING:
1878 if (no_agent_forwarding_flag) {
1879 debug("Authentication agent forwarding not permitted for this authentication.");
1880 goto fail;
1881 }
1882 debug("Received authentication agent forwarding request.");
1883 auth_input_request_forwarding(pw);
1884 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001885
Damien Miller95def091999-11-25 00:26:21 +11001886 case SSH_CMSG_PORT_FORWARD_REQUEST:
1887 if (no_port_forwarding_flag) {
1888 debug("Port forwarding not permitted for this authentication.");
1889 goto fail;
1890 }
1891 debug("Received TCP/IP port forwarding request.");
1892 channel_input_port_forward_request(pw->pw_uid == 0);
1893 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001894
Damien Miller95def091999-11-25 00:26:21 +11001895 case SSH_CMSG_MAX_PACKET_SIZE:
1896 if (packet_set_maxsize(packet_get_int()) < 0)
1897 goto fail;
1898 break;
Damien Miller6162d121999-11-21 13:23:52 +11001899
Damien Miller95def091999-11-25 00:26:21 +11001900 case SSH_CMSG_EXEC_SHELL:
1901 /* Set interactive/non-interactive mode. */
1902 packet_set_interactive(have_pty || display != NULL,
1903 options.keepalives);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001904
Damien Miller95def091999-11-25 00:26:21 +11001905 if (forced_command != NULL)
1906 goto do_forced_command;
1907 debug("Forking shell.");
1908 packet_integrity_check(plen, 0, type);
1909 if (have_pty)
1910 do_exec_pty(NULL, ptyfd, ttyfd, ttyname, pw, term, display, proto, data);
1911 else
1912 do_exec_no_pty(NULL, pw, display, proto, data);
1913 return;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001914
Damien Miller95def091999-11-25 00:26:21 +11001915 case SSH_CMSG_EXEC_CMD:
1916 /* Set interactive/non-interactive mode. */
1917 packet_set_interactive(have_pty || display != NULL,
1918 options.keepalives);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001919
Damien Miller95def091999-11-25 00:26:21 +11001920 if (forced_command != NULL)
1921 goto do_forced_command;
1922 /* Get command from the packet. */
1923 {
1924 int dlen;
1925 command = packet_get_string(&dlen);
1926 debug("Executing command '%.500s'", command);
1927 packet_integrity_check(plen, 4 + dlen, type);
1928 }
1929 if (have_pty)
1930 do_exec_pty(command, ptyfd, ttyfd, ttyname, pw, term, display, proto, data);
1931 else
1932 do_exec_no_pty(command, pw, display, proto, data);
1933 xfree(command);
1934 return;
1935
1936 default:
Damien Miller5428f641999-11-25 11:54:57 +11001937 /*
1938 * Any unknown messages in this phase are ignored,
1939 * and a failure message is returned.
1940 */
Damien Miller95def091999-11-25 00:26:21 +11001941 log("Unknown packet type received after authentication: %d", type);
1942 goto fail;
1943 }
1944
1945 /* The request was successfully processed. */
1946 packet_start(SSH_SMSG_SUCCESS);
1947 packet_send();
1948 packet_write_wait();
1949
1950 /* Enable compression now that we have replied if appropriate. */
1951 if (enable_compression_after_reply) {
1952 enable_compression_after_reply = 0;
1953 packet_start_compression(compression_level);
1954 }
1955 continue;
1956
1957fail:
1958 /* The request failed. */
1959 packet_start(SSH_SMSG_FAILURE);
1960 packet_send();
1961 packet_write_wait();
1962 continue;
1963
1964do_forced_command:
Damien Miller5428f641999-11-25 11:54:57 +11001965 /*
1966 * There is a forced command specified for this login.
1967 * Execute it.
1968 */
Damien Miller95def091999-11-25 00:26:21 +11001969 debug("Executing forced command: %.900s", forced_command);
1970 if (have_pty)
1971 do_exec_pty(forced_command, ptyfd, ttyfd, ttyname, pw, term, display, proto, data);
1972 else
1973 do_exec_no_pty(forced_command, pw, display, proto, data);
1974 return;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001975 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001976}
1977
Damien Miller95def091999-11-25 00:26:21 +11001978/*
1979 * This is called to fork and execute a command when we have no tty. This
1980 * will call do_child from the child, and server_loop from the parent after
1981 * setting up file descriptors and such.
1982 */
1983void
1984do_exec_no_pty(const char *command, struct passwd * pw,
1985 const char *display, const char *auth_proto,
1986 const char *auth_data)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001987{
Damien Miller95def091999-11-25 00:26:21 +11001988 int pid;
1989
1990#ifdef USE_PIPES
1991 int pin[2], pout[2], perr[2];
1992 /* Allocate pipes for communicating with the program. */
1993 if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0)
1994 packet_disconnect("Could not create pipes: %.100s",
1995 strerror(errno));
1996#else /* USE_PIPES */
1997 int inout[2], err[2];
1998 /* Uses socket pairs to communicate with the program. */
1999 if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 ||
2000 socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0)
2001 packet_disconnect("Could not create socket pairs: %.100s",
2002 strerror(errno));
2003#endif /* USE_PIPES */
2004
2005 setproctitle("%s@notty", pw->pw_name);
2006
2007 /* Fork the child. */
2008 if ((pid = fork()) == 0) {
2009 /* Child. Reinitialize the log since the pid has changed. */
2010 log_init(av0, options.log_level, options.log_facility, log_stderr);
2011
Damien Miller5428f641999-11-25 11:54:57 +11002012 /*
2013 * Create a new session and process group since the 4.4BSD
2014 * setlogin() affects the entire process group.
2015 */
Damien Miller95def091999-11-25 00:26:21 +11002016 if (setsid() < 0)
2017 error("setsid failed: %.100s", strerror(errno));
2018
2019#ifdef USE_PIPES
Damien Miller5428f641999-11-25 11:54:57 +11002020 /*
2021 * Redirect stdin. We close the parent side of the socket
2022 * pair, and make the child side the standard input.
2023 */
Damien Miller95def091999-11-25 00:26:21 +11002024 close(pin[1]);
2025 if (dup2(pin[0], 0) < 0)
2026 perror("dup2 stdin");
2027 close(pin[0]);
2028
2029 /* Redirect stdout. */
2030 close(pout[0]);
2031 if (dup2(pout[1], 1) < 0)
2032 perror("dup2 stdout");
2033 close(pout[1]);
2034
2035 /* Redirect stderr. */
2036 close(perr[0]);
2037 if (dup2(perr[1], 2) < 0)
2038 perror("dup2 stderr");
2039 close(perr[1]);
2040#else /* USE_PIPES */
Damien Miller5428f641999-11-25 11:54:57 +11002041 /*
2042 * Redirect stdin, stdout, and stderr. Stdin and stdout will
2043 * use the same socket, as some programs (particularly rdist)
2044 * seem to depend on it.
2045 */
Damien Miller95def091999-11-25 00:26:21 +11002046 close(inout[1]);
2047 close(err[1]);
2048 if (dup2(inout[0], 0) < 0) /* stdin */
2049 perror("dup2 stdin");
2050 if (dup2(inout[0], 1) < 0) /* stdout. Note: same socket as stdin. */
2051 perror("dup2 stdout");
2052 if (dup2(err[0], 2) < 0) /* stderr */
2053 perror("dup2 stderr");
2054#endif /* USE_PIPES */
2055
2056 /* Do processing for the child (exec command etc). */
2057 do_child(command, pw, NULL, display, auth_proto, auth_data, NULL);
2058 /* NOTREACHED */
2059 }
2060 if (pid < 0)
2061 packet_disconnect("fork failed: %.100s", strerror(errno));
2062#ifdef USE_PIPES
2063 /* We are the parent. Close the child sides of the pipes. */
2064 close(pin[0]);
2065 close(pout[1]);
2066 close(perr[1]);
2067
2068 /* Enter the interactive session. */
2069 server_loop(pid, pin[1], pout[0], perr[0]);
2070 /* server_loop has closed pin[1], pout[1], and perr[1]. */
2071#else /* USE_PIPES */
2072 /* We are the parent. Close the child sides of the socket pairs. */
2073 close(inout[0]);
2074 close(err[0]);
2075
Damien Miller5428f641999-11-25 11:54:57 +11002076 /*
2077 * Enter the interactive session. Note: server_loop must be able to
2078 * handle the case that fdin and fdout are the same.
2079 */
Damien Miller95def091999-11-25 00:26:21 +11002080 server_loop(pid, inout[1], inout[1], err[1]);
2081 /* server_loop has closed inout[1] and err[1]. */
2082#endif /* USE_PIPES */
2083}
2084
2085struct pty_cleanup_context {
2086 const char *ttyname;
2087 int pid;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002088};
2089
Damien Miller95def091999-11-25 00:26:21 +11002090/*
2091 * Function to perform cleanup if we get aborted abnormally (e.g., due to a
2092 * dropped connection).
2093 */
2094void
2095pty_cleanup_proc(void *context)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002096{
Damien Miller95def091999-11-25 00:26:21 +11002097 struct pty_cleanup_context *cu = context;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002098
Damien Miller95def091999-11-25 00:26:21 +11002099 debug("pty_cleanup_proc called");
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002100
Damien Miller95def091999-11-25 00:26:21 +11002101 /* Record that the user has logged out. */
2102 record_logout(cu->pid, cu->ttyname);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002103
Damien Miller95def091999-11-25 00:26:21 +11002104 /* Release the pseudo-tty. */
2105 pty_release(cu->ttyname);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002106}
2107
Damien Miller95def091999-11-25 00:26:21 +11002108/*
2109 * This is called to fork and execute a command when we have a tty. This
2110 * will call do_child from the child, and server_loop from the parent after
2111 * setting up file descriptors, controlling tty, updating wtmp, utmp,
2112 * lastlog, and other such operations.
2113 */
2114void
2115do_exec_pty(const char *command, int ptyfd, int ttyfd,
2116 const char *ttyname, struct passwd * pw, const char *term,
2117 const char *display, const char *auth_proto,
2118 const char *auth_data)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002119{
Damien Miller95def091999-11-25 00:26:21 +11002120 int pid, fdout;
2121 const char *hostname;
2122 time_t last_login_time;
2123 char buf[100], *time_string;
2124 FILE *f;
2125 char line[256];
2126 struct stat st;
2127 int quiet_login;
2128 struct sockaddr_in from;
2129 int fromlen;
2130 struct pty_cleanup_context cleanup_context;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002131
Damien Miller95def091999-11-25 00:26:21 +11002132 /* Get remote host name. */
2133 hostname = get_canonical_hostname();
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002134
Damien Miller5428f641999-11-25 11:54:57 +11002135 /*
2136 * Get the time when the user last logged in. Buf will be set to
2137 * contain the hostname the last login was from.
2138 */
Damien Miller95def091999-11-25 00:26:21 +11002139 if (!options.use_login) {
2140 last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
2141 buf, sizeof(buf));
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002142 }
Damien Miller95def091999-11-25 00:26:21 +11002143 setproctitle("%s@%s", pw->pw_name, strrchr(ttyname, '/') + 1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002144
Damien Miller95def091999-11-25 00:26:21 +11002145 /* Fork the child. */
2146 if ((pid = fork()) == 0) {
2147 pid = getpid();
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002148
Damien Miller95def091999-11-25 00:26:21 +11002149 /* Child. Reinitialize the log because the pid has
2150 changed. */
2151 log_init(av0, options.log_level, options.log_facility, log_stderr);
2152
2153 /* Close the master side of the pseudo tty. */
2154 close(ptyfd);
2155
2156 /* Make the pseudo tty our controlling tty. */
2157 pty_make_controlling_tty(&ttyfd, ttyname);
2158
2159 /* Redirect stdin from the pseudo tty. */
2160 if (dup2(ttyfd, fileno(stdin)) < 0)
2161 error("dup2 stdin failed: %.100s", strerror(errno));
2162
2163 /* Redirect stdout to the pseudo tty. */
2164 if (dup2(ttyfd, fileno(stdout)) < 0)
2165 error("dup2 stdin failed: %.100s", strerror(errno));
2166
2167 /* Redirect stderr to the pseudo tty. */
2168 if (dup2(ttyfd, fileno(stderr)) < 0)
2169 error("dup2 stdin failed: %.100s", strerror(errno));
2170
2171 /* Close the extra descriptor for the pseudo tty. */
2172 close(ttyfd);
2173
Damien Miller5428f641999-11-25 11:54:57 +11002174 /*
2175 * Get IP address of client. This is needed because we want
2176 * to record where the user logged in from. If the
2177 * connection is not a socket, let the ip address be 0.0.0.0.
2178 */
Damien Miller95def091999-11-25 00:26:21 +11002179 memset(&from, 0, sizeof(from));
2180 if (packet_get_connection_in() == packet_get_connection_out()) {
2181 fromlen = sizeof(from);
2182 if (getpeername(packet_get_connection_in(),
2183 (struct sockaddr *) & from, &fromlen) < 0) {
2184 debug("getpeername: %.100s", strerror(errno));
2185 fatal_cleanup();
2186 }
2187 }
2188 /* Record that there was a login on that terminal. */
2189 record_login(pid, ttyname, pw->pw_name, pw->pw_uid, hostname,
2190 &from);
2191
2192 /* Check if .hushlogin exists. */
2193 snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir);
2194 quiet_login = stat(line, &st) >= 0;
Damien Miller356a0b01999-11-08 15:30:59 +11002195
2196#ifdef HAVE_LIBPAM
Damien Miller95def091999-11-25 00:26:21 +11002197 /* output the results of the pamconv() */
2198 if (!quiet_login && pamconv_msg != NULL)
2199 fprintf(stderr, pamconv_msg);
Damien Miller356a0b01999-11-08 15:30:59 +11002200#endif
Damien Miller95def091999-11-25 00:26:21 +11002201
Damien Miller5428f641999-11-25 11:54:57 +11002202 /*
2203 * If the user has logged in before, display the time of last
2204 * login. However, don't display anything extra if a command
2205 * has been specified (so that ssh can be used to execute
2206 * commands on a remote machine without users knowing they
2207 * are going to another machine). Login(1) will do this for
2208 * us as well, so check if login(1) is used
2209 */
Damien Miller95def091999-11-25 00:26:21 +11002210 if (command == NULL && last_login_time != 0 && !quiet_login &&
2211 !options.use_login) {
2212 /* Convert the date to a string. */
2213 time_string = ctime(&last_login_time);
2214 /* Remove the trailing newline. */
2215 if (strchr(time_string, '\n'))
2216 *strchr(time_string, '\n') = 0;
2217 /* Display the last login time. Host if displayed
2218 if known. */
2219 if (strcmp(buf, "") == 0)
2220 printf("Last login: %s\r\n", time_string);
2221 else
2222 printf("Last login: %s from %s\r\n", time_string, buf);
2223 }
Damien Miller5428f641999-11-25 11:54:57 +11002224 /*
2225 * Print /etc/motd unless a command was specified or printing
2226 * it was disabled in server options or login(1) will be
2227 * used. Note that some machines appear to print it in
2228 * /etc/profile or similar.
2229 */
Damien Miller95def091999-11-25 00:26:21 +11002230 if (command == NULL && options.print_motd && !quiet_login &&
2231 !options.use_login) {
2232 /* Print /etc/motd if it exists. */
2233 f = fopen("/etc/motd", "r");
2234 if (f) {
2235 while (fgets(line, sizeof(line), f))
2236 fputs(line, stdout);
2237 fclose(f);
2238 }
2239 }
2240 /* Do common processing for the child, such as execing the command. */
2241 do_child(command, pw, term, display, auth_proto, auth_data, ttyname);
2242 /* NOTREACHED */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002243 }
Damien Miller95def091999-11-25 00:26:21 +11002244 if (pid < 0)
2245 packet_disconnect("fork failed: %.100s", strerror(errno));
2246 /* Parent. Close the slave side of the pseudo tty. */
2247 close(ttyfd);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002248
Damien Miller5428f641999-11-25 11:54:57 +11002249 /*
2250 * Create another descriptor of the pty master side for use as the
2251 * standard input. We could use the original descriptor, but this
2252 * simplifies code in server_loop. The descriptor is bidirectional.
2253 */
Damien Miller95def091999-11-25 00:26:21 +11002254 fdout = dup(ptyfd);
2255 if (fdout < 0)
2256 packet_disconnect("dup failed: %.100s", strerror(errno));
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002257
Damien Miller5428f641999-11-25 11:54:57 +11002258 /*
2259 * Add a cleanup function to clear the utmp entry and record logout
2260 * time in case we call fatal() (e.g., the connection gets closed).
2261 */
Damien Miller95def091999-11-25 00:26:21 +11002262 cleanup_context.pid = pid;
2263 cleanup_context.ttyname = ttyname;
2264 fatal_add_cleanup(pty_cleanup_proc, (void *) &cleanup_context);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002265
Damien Miller95def091999-11-25 00:26:21 +11002266 /* Enter interactive session. */
2267 server_loop(pid, ptyfd, fdout, -1);
2268 /* server_loop has not closed ptyfd and fdout. */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002269
Damien Miller95def091999-11-25 00:26:21 +11002270 /* Cancel the cleanup function. */
2271 fatal_remove_cleanup(pty_cleanup_proc, (void *) &cleanup_context);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002272
Damien Miller95def091999-11-25 00:26:21 +11002273 /* Record that the user has logged out. */
2274 record_logout(pid, ttyname);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002275
Damien Miller95def091999-11-25 00:26:21 +11002276 /* Release the pseudo-tty. */
2277 pty_release(ttyname);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002278
Damien Miller5428f641999-11-25 11:54:57 +11002279 /*
2280 * Close the server side of the socket pairs. We must do this after
2281 * the pty cleanup, so that another process doesn't get this pty
2282 * while we're still cleaning up.
2283 */
Damien Miller95def091999-11-25 00:26:21 +11002284 close(ptyfd);
2285 close(fdout);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002286}
2287
Damien Miller95def091999-11-25 00:26:21 +11002288/*
2289 * Sets the value of the given variable in the environment. If the variable
2290 * already exists, its value is overriden.
2291 */
2292void
2293child_set_env(char ***envp, unsigned int *envsizep, const char *name,
2294 const char *value)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002295{
Damien Miller95def091999-11-25 00:26:21 +11002296 unsigned int i, namelen;
2297 char **env;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002298
Damien Miller5428f641999-11-25 11:54:57 +11002299 /*
2300 * Find the slot where the value should be stored. If the variable
2301 * already exists, we reuse the slot; otherwise we append a new slot
2302 * at the end of the array, expanding if necessary.
2303 */
Damien Miller95def091999-11-25 00:26:21 +11002304 env = *envp;
2305 namelen = strlen(name);
2306 for (i = 0; env[i]; i++)
2307 if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
2308 break;
2309 if (env[i]) {
Damien Miller5428f641999-11-25 11:54:57 +11002310 /* Reuse the slot. */
Damien Miller95def091999-11-25 00:26:21 +11002311 xfree(env[i]);
2312 } else {
Damien Miller5428f641999-11-25 11:54:57 +11002313 /* New variable. Expand if necessary. */
Damien Miller95def091999-11-25 00:26:21 +11002314 if (i >= (*envsizep) - 1) {
2315 (*envsizep) += 50;
2316 env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *));
2317 }
2318 /* Need to set the NULL pointer at end of array beyond the new slot. */
2319 env[i + 1] = NULL;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002320 }
2321
Damien Miller95def091999-11-25 00:26:21 +11002322 /* Allocate space and format the variable in the appropriate slot. */
2323 env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
2324 snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002325}
2326
Damien Miller95def091999-11-25 00:26:21 +11002327/*
2328 * Reads environment variables from the given file and adds/overrides them
2329 * into the environment. If the file does not exist, this does nothing.
2330 * Otherwise, it must consist of empty lines, comments (line starts with '#')
2331 * and assignments of the form name=value. No other forms are allowed.
2332 */
2333void
2334read_environment_file(char ***env, unsigned int *envsize,
2335 const char *filename)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002336{
Damien Miller95def091999-11-25 00:26:21 +11002337 FILE *f;
2338 char buf[4096];
2339 char *cp, *value;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002340
Damien Miller95def091999-11-25 00:26:21 +11002341 f = fopen(filename, "r");
2342 if (!f)
2343 return;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002344
Damien Miller95def091999-11-25 00:26:21 +11002345 while (fgets(buf, sizeof(buf), f)) {
Damien Miller5428f641999-11-25 11:54:57 +11002346 for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
2347 ;
Damien Miller95def091999-11-25 00:26:21 +11002348 if (!*cp || *cp == '#' || *cp == '\n')
2349 continue;
Damien Miller95def091999-11-25 00:26:21 +11002350 if (strchr(cp, '\n'))
2351 *strchr(cp, '\n') = '\0';
Damien Miller95def091999-11-25 00:26:21 +11002352 value = strchr(cp, '=');
2353 if (value == NULL) {
2354 fprintf(stderr, "Bad line in %.100s: %.200s\n", filename, buf);
2355 continue;
2356 }
Damien Miller5428f641999-11-25 11:54:57 +11002357 /* Replace the equals sign by nul, and advance value to the value string. */
Damien Miller95def091999-11-25 00:26:21 +11002358 *value = '\0';
2359 value++;
Damien Miller95def091999-11-25 00:26:21 +11002360 child_set_env(env, envsize, cp, value);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002361 }
Damien Miller95def091999-11-25 00:26:21 +11002362 fclose(f);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002363}
2364
Damien Miller95def091999-11-25 00:26:21 +11002365/*
2366 * Performs common processing for the child, such as setting up the
2367 * environment, closing extra file descriptors, setting the user and group
2368 * ids, and executing the command or shell.
2369 */
2370void
2371do_child(const char *command, struct passwd * pw, const char *term,
2372 const char *display, const char *auth_proto,
2373 const char *auth_data, const char *ttyname)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002374{
Damien Miller95def091999-11-25 00:26:21 +11002375 const char *shell, *cp = NULL;
2376 char buf[256];
2377 FILE *f;
2378 unsigned int envsize, i;
2379 char **env;
2380 extern char **environ;
2381 struct stat st;
2382 char *argv[10];
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002383
Damien Miller356a0b01999-11-08 15:30:59 +11002384#ifndef HAVE_LIBPAM /* pam_nologin handles this */
Damien Miller95def091999-11-25 00:26:21 +11002385 /* Check /etc/nologin. */
2386 f = fopen("/etc/nologin", "r");
2387 if (f) {
2388 /* /etc/nologin exists. Print its contents and exit. */
2389 while (fgets(buf, sizeof(buf), f))
2390 fputs(buf, stderr);
2391 fclose(f);
2392 if (pw->pw_uid != 0)
2393 exit(254);
2394 }
Damien Miller776af5d1999-11-12 08:49:09 +11002395#endif /* HAVE_LIBPAM */
2396
2397#ifdef HAVE_SETLOGIN
Damien Miller95def091999-11-25 00:26:21 +11002398 /* Set login name in the kernel. */
2399 if (setlogin(pw->pw_name) < 0)
2400 error("setlogin failed: %s", strerror(errno));
Damien Miller776af5d1999-11-12 08:49:09 +11002401#endif /* HAVE_SETLOGIN */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002402
Damien Miller95def091999-11-25 00:26:21 +11002403 /* Set uid, gid, and groups. */
2404 /* Login(1) does this as well, and it needs uid 0 for the "-h"
2405 switch, so we let login(1) to this for us. */
2406 if (!options.use_login) {
2407 if (getuid() == 0 || geteuid() == 0) {
2408 if (setgid(pw->pw_gid) < 0) {
2409 perror("setgid");
2410 exit(1);
2411 }
2412 /* Initialize the group list. */
2413 if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
2414 perror("initgroups");
2415 exit(1);
2416 }
2417 endgrent();
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002418
Damien Miller95def091999-11-25 00:26:21 +11002419 /* Permanently switch to the desired uid. */
2420 permanently_set_uid(pw->pw_uid);
2421 }
2422 if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
2423 fatal("Failed to set uids to %d.", (int) pw->pw_uid);
2424 }
Damien Miller5428f641999-11-25 11:54:57 +11002425 /*
2426 * Get the shell from the password data. An empty shell field is
2427 * legal, and means /bin/sh.
2428 */
Damien Miller95def091999-11-25 00:26:21 +11002429 shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002430
2431#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +11002432 /* Try to get AFS tokens for the local cell. */
2433 if (k_hasafs()) {
2434 char cell[64];
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002435
Damien Miller95def091999-11-25 00:26:21 +11002436 if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
2437 krb_afslog(cell, 0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002438
Damien Miller95def091999-11-25 00:26:21 +11002439 krb_afslog(0, 0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002440 }
Damien Miller95def091999-11-25 00:26:21 +11002441#endif /* AFS */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002442
Damien Miller5428f641999-11-25 11:54:57 +11002443 /* Initialize the environment. */
Damien Miller95def091999-11-25 00:26:21 +11002444 envsize = 100;
2445 env = xmalloc(envsize * sizeof(char *));
2446 env[0] = NULL;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002447
Damien Miller95def091999-11-25 00:26:21 +11002448 if (!options.use_login) {
2449 /* Set basic environment. */
2450 child_set_env(&env, &envsize, "USER", pw->pw_name);
2451 child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
2452 child_set_env(&env, &envsize, "HOME", pw->pw_dir);
2453 child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002454
Damien Miller95def091999-11-25 00:26:21 +11002455 snprintf(buf, sizeof buf, "%.200s/%.50s",
2456 _PATH_MAILDIR, pw->pw_name);
2457 child_set_env(&env, &envsize, "MAIL", buf);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002458
Damien Miller95def091999-11-25 00:26:21 +11002459 /* Normal systems set SHELL by default. */
2460 child_set_env(&env, &envsize, "SHELL", shell);
2461 }
Damien Miller95def091999-11-25 00:26:21 +11002462 if (getenv("TZ"))
2463 child_set_env(&env, &envsize, "TZ", getenv("TZ"));
2464
2465 /* Set custom environment options from RSA authentication. */
2466 while (custom_environment) {
2467 struct envstring *ce = custom_environment;
2468 char *s = ce->s;
2469 int i;
2470 for (i = 0; s[i] != '=' && s[i]; i++);
2471 if (s[i] == '=') {
2472 s[i] = 0;
2473 child_set_env(&env, &envsize, s, s + i + 1);
2474 }
2475 custom_environment = ce->next;
2476 xfree(ce->s);
2477 xfree(ce);
2478 }
2479
Damien Miller95def091999-11-25 00:26:21 +11002480 snprintf(buf, sizeof buf, "%.50s %d %d",
2481 get_remote_ipaddr(), get_remote_port(), options.port);
2482 child_set_env(&env, &envsize, "SSH_CLIENT", buf);
2483
Damien Miller95def091999-11-25 00:26:21 +11002484 if (ttyname)
2485 child_set_env(&env, &envsize, "SSH_TTY", ttyname);
Damien Miller95def091999-11-25 00:26:21 +11002486 if (term)
2487 child_set_env(&env, &envsize, "TERM", term);
Damien Miller95def091999-11-25 00:26:21 +11002488 if (display)
2489 child_set_env(&env, &envsize, "DISPLAY", display);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002490
2491#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +11002492 {
2493 extern char *ticket;
2494
2495 if (ticket)
2496 child_set_env(&env, &envsize, "KRBTKFILE", ticket);
2497 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002498#endif /* KRB4 */
2499
Damien Miller94388161999-10-29 09:57:31 +10002500#ifdef HAVE_LIBPAM
Damien Miller95def091999-11-25 00:26:21 +11002501 /* Pull in any environment variables that may have been set by PAM. */
2502 {
2503 char *equals, var_name[512], var_val[512];
2504 char **pam_env = pam_getenvlist((pam_handle_t *)pamh);
2505 int i;
2506 for(i = 0; pam_env && pam_env[i]; i++) {
2507 equals = strstr(pam_env[i], "=");
2508 if ((strlen(pam_env[i]) < (sizeof(var_name) - 1)) && (equals != NULL))
2509 {
Damien Millerdc33fc31999-12-04 20:24:48 +11002510 debug("PAM environment: %s=%s", var_name, var_val);
Damien Miller95def091999-11-25 00:26:21 +11002511 memset(var_name, '\0', sizeof(var_name));
2512 memset(var_val, '\0', sizeof(var_val));
2513 strncpy(var_name, pam_env[i], equals - pam_env[i]);
2514 strcpy(var_val, equals + 1);
2515 child_set_env(&env, &envsize, var_name, var_val);
2516 }
2517 }
2518 }
Damien Miller94388161999-10-29 09:57:31 +10002519#endif /* HAVE_LIBPAM */
2520
Damien Miller95def091999-11-25 00:26:21 +11002521 if (xauthfile)
2522 child_set_env(&env, &envsize, "XAUTHORITY", xauthfile);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002523
Damien Miller95def091999-11-25 00:26:21 +11002524 if (auth_get_socket_name() != NULL)
2525 child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
2526 auth_get_socket_name());
Damien Miller776af5d1999-11-12 08:49:09 +11002527
Damien Miller5428f641999-11-25 11:54:57 +11002528 /* read $HOME/.ssh/environment. */
Damien Miller95def091999-11-25 00:26:21 +11002529 if (!options.use_login) {
2530 snprintf(buf, sizeof buf, "%.200s/.ssh/environment", pw->pw_dir);
2531 read_environment_file(&env, &envsize, buf);
2532 }
Damien Miller95def091999-11-25 00:26:21 +11002533 if (debug_flag) {
Damien Miller5428f641999-11-25 11:54:57 +11002534 /* dump the environment */
Damien Miller95def091999-11-25 00:26:21 +11002535 fprintf(stderr, "Environment:\n");
2536 for (i = 0; env[i]; i++)
2537 fprintf(stderr, " %.200s\n", env[i]);
2538 }
Damien Miller5428f641999-11-25 11:54:57 +11002539 /*
2540 * Close the connection descriptors; note that this is the child, and
2541 * the server will still have the socket open, and it is important
2542 * that we do not shutdown it. Note that the descriptors cannot be
2543 * closed before building the environment, as we call
2544 * get_remote_ipaddr there.
2545 */
Damien Miller95def091999-11-25 00:26:21 +11002546 if (packet_get_connection_in() == packet_get_connection_out())
2547 close(packet_get_connection_in());
2548 else {
2549 close(packet_get_connection_in());
2550 close(packet_get_connection_out());
2551 }
Damien Miller5428f641999-11-25 11:54:57 +11002552 /*
2553 * Close all descriptors related to channels. They will still remain
2554 * open in the parent.
2555 */
2556 /* XXX better use close-on-exec? -markus */
Damien Miller95def091999-11-25 00:26:21 +11002557 channel_close_all();
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002558
Damien Miller5428f641999-11-25 11:54:57 +11002559 /*
2560 * Close any extra file descriptors. Note that there may still be
2561 * descriptors left by system functions. They will be closed later.
2562 */
Damien Miller95def091999-11-25 00:26:21 +11002563 endpwent();
2564 endhostent();
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002565
Damien Miller5428f641999-11-25 11:54:57 +11002566 /*
2567 * Close any extra open file descriptors so that we don\'t have them
2568 * hanging around in clients. Note that we want to do this after
2569 * initgroups, because at least on Solaris 2.3 it leaves file
2570 * descriptors open.
2571 */
Damien Miller95def091999-11-25 00:26:21 +11002572 for (i = 3; i < 64; i++)
2573 close(i);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002574
Damien Miller95def091999-11-25 00:26:21 +11002575 /* Change current directory to the user\'s home directory. */
2576 if (chdir(pw->pw_dir) < 0)
2577 fprintf(stderr, "Could not chdir to home directory %s: %s\n",
2578 pw->pw_dir, strerror(errno));
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002579
Damien Miller5428f641999-11-25 11:54:57 +11002580 /*
2581 * Must take new environment into use so that .ssh/rc, /etc/sshrc and
2582 * xauth are run in the proper environment.
2583 */
Damien Miller95def091999-11-25 00:26:21 +11002584 environ = env;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002585
Damien Miller5428f641999-11-25 11:54:57 +11002586 /*
2587 * Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first
2588 * in this order).
2589 */
Damien Miller95def091999-11-25 00:26:21 +11002590 if (!options.use_login) {
2591 if (stat(SSH_USER_RC, &st) >= 0) {
2592 if (debug_flag)
2593 fprintf(stderr, "Running /bin/sh %s\n", SSH_USER_RC);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002594
Damien Miller95def091999-11-25 00:26:21 +11002595 f = popen("/bin/sh " SSH_USER_RC, "w");
2596 if (f) {
2597 if (auth_proto != NULL && auth_data != NULL)
2598 fprintf(f, "%s %s\n", auth_proto, auth_data);
2599 pclose(f);
2600 } else
2601 fprintf(stderr, "Could not run %s\n", SSH_USER_RC);
2602 } else if (stat(SSH_SYSTEM_RC, &st) >= 0) {
2603 if (debug_flag)
2604 fprintf(stderr, "Running /bin/sh %s\n", SSH_SYSTEM_RC);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002605
Damien Miller95def091999-11-25 00:26:21 +11002606 f = popen("/bin/sh " SSH_SYSTEM_RC, "w");
2607 if (f) {
2608 if (auth_proto != NULL && auth_data != NULL)
2609 fprintf(f, "%s %s\n", auth_proto, auth_data);
2610 pclose(f);
2611 } else
2612 fprintf(stderr, "Could not run %s\n", SSH_SYSTEM_RC);
2613 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002614#ifdef XAUTH_PATH
Damien Miller95def091999-11-25 00:26:21 +11002615 else {
Damien Miller5428f641999-11-25 11:54:57 +11002616 /* Add authority data to .Xauthority if appropriate. */
Damien Miller95def091999-11-25 00:26:21 +11002617 if (auth_proto != NULL && auth_data != NULL) {
2618 if (debug_flag)
2619 fprintf(stderr, "Running %.100s add %.100s %.100s %.100s\n",
2620 XAUTH_PATH, display, auth_proto, auth_data);
2621
2622 f = popen(XAUTH_PATH " -q -", "w");
2623 if (f) {
2624 fprintf(f, "add %s %s %s\n", display, auth_proto, auth_data);
2625 fclose(f);
2626 } else
2627 fprintf(stderr, "Could not run %s -q -\n", XAUTH_PATH);
2628 }
2629 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002630#endif /* XAUTH_PATH */
2631
Damien Miller95def091999-11-25 00:26:21 +11002632 /* Get the last component of the shell name. */
2633 cp = strrchr(shell, '/');
2634 if (cp)
2635 cp++;
2636 else
2637 cp = shell;
2638 }
Damien Miller5428f641999-11-25 11:54:57 +11002639 /*
2640 * If we have no command, execute the shell. In this case, the shell
2641 * name to be passed in argv[0] is preceded by '-' to indicate that
2642 * this is a login shell.
2643 */
Damien Miller95def091999-11-25 00:26:21 +11002644 if (!command) {
2645 if (!options.use_login) {
2646 char buf[256];
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002647
Damien Miller5428f641999-11-25 11:54:57 +11002648 /*
2649 * Check for mail if we have a tty and it was enabled
2650 * in server options.
2651 */
Damien Miller95def091999-11-25 00:26:21 +11002652 if (ttyname && options.check_mail) {
2653 char *mailbox;
2654 struct stat mailstat;
2655 mailbox = getenv("MAIL");
2656 if (mailbox != NULL) {
2657 if (stat(mailbox, &mailstat) != 0 || mailstat.st_size == 0)
2658 printf("No mail.\n");
2659 else if (mailstat.st_mtime < mailstat.st_atime)
2660 printf("You have mail.\n");
2661 else
2662 printf("You have new mail.\n");
2663 }
2664 }
2665 /* Start the shell. Set initial character to '-'. */
2666 buf[0] = '-';
2667 strncpy(buf + 1, cp, sizeof(buf) - 1);
2668 buf[sizeof(buf) - 1] = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002669
Damien Miller95def091999-11-25 00:26:21 +11002670 /* Execute the shell. */
2671 argv[0] = buf;
2672 argv[1] = NULL;
2673 execve(shell, argv, env);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002674
Damien Miller95def091999-11-25 00:26:21 +11002675 /* Executing the shell failed. */
2676 perror(shell);
2677 exit(1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002678
Damien Miller95def091999-11-25 00:26:21 +11002679 } else {
2680 /* Launch login(1). */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002681
Damien Miller95def091999-11-25 00:26:21 +11002682 execl(LOGIN_PROGRAM, "login", "-h", get_remote_ipaddr(),
2683 "-p", "-f", "--", pw->pw_name, NULL);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002684
Damien Miller95def091999-11-25 00:26:21 +11002685 /* Login couldn't be executed, die. */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002686
Damien Miller95def091999-11-25 00:26:21 +11002687 perror("login");
2688 exit(1);
2689 }
2690 }
Damien Miller5428f641999-11-25 11:54:57 +11002691 /*
2692 * Execute the command using the user's shell. This uses the -c
2693 * option to execute the command.
2694 */
Damien Miller95def091999-11-25 00:26:21 +11002695 argv[0] = (char *) cp;
2696 argv[1] = "-c";
2697 argv[2] = (char *) command;
2698 argv[3] = NULL;
2699 execve(shell, argv, env);
2700 perror(shell);
2701 exit(1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002702}