#include "uidswap.h"
#include "compat.h"
+#ifdef HAVE_MAILLOCK_H
+# include <maillock.h>
+#endif
+
#ifdef LIBWRAP
#include <tcpd.h>
#include <syslog.h>
#define O_NOCTTY 0
#endif
-#ifdef KRB4
-char *ticket = NULL;
-#endif /* KRB4 */
-
/* Local Xauthority file. */
-char *xauthfile = NULL;
+static char *xauthfile = NULL;
/* Server configuration options. */
ServerOptions options;
/* Flag indicating that the daemon is being started from inetd. */
int inetd_flag = 0;
+/* debug goes to stderr unless inetd_flag is set */
+int log_stderr = 0;
+
/* argv[0] without path. */
char *av0;
RSA *public_key;
/* Prototypes for various functions defined later in this file. */
-void do_connection(int privileged_port);
-void do_authentication(char *user, int privileged_port);
-void eat_packets_and_disconnect(const char *user);
+void do_connection();
+void do_authentication(char *user);
+void do_authloop(struct passwd *pw);
+void do_fake_authloop(char *user);
void do_authenticated(struct passwd *pw);
void do_exec_pty(const char *command, int ptyfd, int ttyfd,
const char *ttyname, struct passwd *pw, const char *term,
void do_child(const char *command, struct passwd *pw, const char *term,
const char *display, const char *auth_proto,
const char *auth_data, const char *ttyname);
+
#ifdef HAVE_LIBPAM
static int pamconv(int num_msg, const struct pam_message **msg,
- struct pam_response **resp, void *appdata_ptr);
-void do_pam_account_and_session(const char *username, const char *password,
- const char *remote_user, const char *remote_host);
+ struct pam_response **resp, void *appdata_ptr);
+void do_pam_account_and_session(char *username, char *remote_user,
+ const char *remote_host);
void pam_cleanup_proc(void *context);
static struct pam_conv conv = {
};
struct pam_handle_t *pamh = NULL;
const char *pampasswd = NULL;
+char *pamconv_msg = NULL;
static int pamconv(int num_msg, const struct pam_message **msg,
struct pam_response **resp, void *appdata_ptr)
{
- int count = 0;
- struct pam_response *reply = NULL;
+ struct pam_response *reply;
+ int count;
+ size_t msg_len;
+ char *p;
/* PAM will free this later */
reply = malloc(num_msg * sizeof(*reply));
case PAM_TEXT_INFO:
reply[count].resp_retcode = PAM_SUCCESS;
reply[count].resp = xstrdup("");
+
+ if (msg[count]->msg == NULL)
+ break;
+ debug("Adding PAM message: %s", msg[count]->msg);
+
+ msg_len = strlen(msg[count]->msg);
+ if (pamconv_msg)
+ {
+ size_t n = strlen(pamconv_msg);
+ pamconv_msg = xrealloc(pamconv_msg, n + msg_len + 2);
+ p = pamconv_msg + n;
+ }
+ else
+ pamconv_msg = p = xmalloc(msg_len + 2);
+ memcpy(p, msg[count]->msg, msg_len);
+ p[msg_len] = '\n';
+ p[msg_len + 1] = '\0';
break;
case PAM_PROMPT_ECHO_ON:
}
}
-void do_pam_account_and_session(const char *username, const char *password, const char *remote_user, const char *remote_host)
+void do_pam_account_and_session(char *username, char *remote_user,
+ const char *remote_host)
{
int pam_retval;
if (pam_retval != PAM_SUCCESS)
{
log("PAM set rhost failed: %.200s", pam_strerror((pam_handle_t *)pamh, pam_retval));
- eat_packets_and_disconnect(username);
+ do_fake_authloop(username);
}
}
if (pam_retval != PAM_SUCCESS)
{
log("PAM set ruser failed: %.200s", pam_strerror((pam_handle_t *)pamh, pam_retval));
- eat_packets_and_disconnect(username);
+ do_fake_authloop(username);
}
}
if (pam_retval != PAM_SUCCESS)
{
log("PAM rejected by account configuration: %.200s", pam_strerror((pam_handle_t *)pamh, pam_retval));
- eat_packets_and_disconnect(username);
+ do_fake_authloop(username);
}
pam_retval = pam_open_session((pam_handle_t *)pamh, 0);
if (pam_retval != PAM_SUCCESS)
{
log("PAM session setup failed: %.200s", pam_strerror((pam_handle_t *)pamh, pam_retval));
- eat_packets_and_disconnect(username);
+ do_fake_authloop(username);
}
}
#endif /* HAVE_LIBPAM */
struct sockaddr_in sin;
char buf[100]; /* Must not be larger than remote_version. */
char remote_version[100]; /* Must be at least as big as buf. */
+ int remote_port;
char *comment;
FILE *f;
struct linger linger;
break;
case 'd':
debug_flag = 1;
+ options.log_level = SYSLOG_LEVEL_DEBUG;
break;
case 'i':
inetd_flag = 1;
silentrsa = 1;
break;
case 'q':
- options.quiet_mode = 1;
+ options.log_level = SYSLOG_LEVEL_QUIET;
break;
case 'b':
options.server_key_bits = atoi(optarg);
exit(1);
}
- /* Initialize the log (it is reinitialized below in case we forked). */
- log_init(av0, debug_flag && !inetd_flag,
- debug_flag || options.fascist_logging,
- options.quiet_mode, options.log_facility);
+ /* Force logging to stderr while loading the private host key
+ unless started from inetd */
+ log_init(av0, options.log_level, options.log_facility, !inetd_flag);
debug("sshd version %.100s", SSH_VERSION);
sensitive_data.host_key = RSA_new();
+ errno = 0;
/* Load the host key. It must have empty passphrase. */
if (!load_private_key(options.host_key_file, "",
sensitive_data.host_key, &comment))
{
- if (debug_flag)
- fprintf(stderr, "Could not load host key: %s: %s\n",
- options.host_key_file, strerror(errno));
- else
- {
- int err = errno;
- log_init(av0, !inetd_flag, 1, 0, options.log_facility);
- error("Could not load host key: %.200s: %.100s",
- options.host_key_file, strerror(err));
- }
+ error("Could not load host key: %.200s: %.100s",
+ options.host_key_file, strerror(errno));
exit(1);
}
xfree(comment);
+ /* Initialize the log (it is reinitialized below in case we forked). */
+ if (debug_flag && !inetd_flag)
+ log_stderr = 1;
+ log_init(av0, options.log_level, options.log_facility, log_stderr);
+
/* If not in debugging mode, and not started from inetd, disconnect from
the controlling terminal, and fork. The original process exits. */
if (!debug_flag && !inetd_flag)
}
/* Reinitialize the log (because of the fork above). */
- log_init(av0, debug_flag && !inetd_flag,
- debug_flag || options.fascist_logging,
- options.quiet_mode, options.log_facility);
+ log_init(av0, options.log_level, options.log_facility, log_stderr);
/* Check that server and host key lengths differ sufficiently. This is
necessary to make double encryption work with rsaref. Oh, I hate
close(listen_sock);
sock_in = newsock;
sock_out = newsock;
- log_init(av0, debug_flag && !inetd_flag,
- options.fascist_logging || debug_flag,
- options.quiet_mode, options.log_facility);
+ log_init(av0, options.log_level, options.log_facility, log_stderr);
break;
}
}
have a key. */
packet_set_connection(sock_in, sock_out);
+ remote_port = get_remote_port();
+
/* Check whether logins are denied from this host. */
#ifdef LIBWRAP
{
close(sock_out);
refuse(&req);
}
- log("Connection from %.500s port %d",
- eval_client(&req), get_remote_port());
+ log("Connection from %.500s port %d", eval_client(&req), remote_port);
}
#else
/* Log the connection. */
- log("Connection from %.100s port %d",
- get_remote_ipaddr(), get_remote_port());
+ log("Connection from %.100s port %d", get_remote_ipaddr(), remote_port);
#endif /* LIBWRAP */
/* We don\'t want to listen forever unless the other side successfully
}
}
+ /* Check that the connection comes from a privileged port.
+ Rhosts- and Rhosts-RSA-Authentication only make sense
+ from priviledged programs.
+ Of course, if the intruder has root access on his local machine,
+ he can connect from any port. So do not use these authentication
+ methods from machines that you do not trust. */
+ if (remote_port >= IPPORT_RESERVED ||
+ remote_port < IPPORT_RESERVED / 2)
+ {
+ options.rhosts_authentication = 0;
+ options.rhosts_rsa_authentication = 0;
+ }
+
packet_set_nonblocking();
- /* Handle the connection. We pass as argument whether the connection
- came from a privileged port. */
- do_connection(get_remote_port() < IPPORT_RESERVED);
+ /* Handle the connection. */
+ do_connection();
#ifdef KRB4
/* Cleanup user's ticket cache file. */
been exchanged. This sends server key and performs the key exchange.
Server and host keys will no longer be needed after this functions. */
-void do_connection(int privileged_port)
+void
+do_connection()
{
- int i;
+ int i, len;
BIGNUM *session_key_int;
unsigned char session_key[SSH_SESSION_KEY_LENGTH];
unsigned char check_bytes[8];
if (BN_cmp(sensitive_data.private_key->n, sensitive_data.host_key->n) > 0)
{
/* Private key has bigger modulus. */
- assert(BN_num_bits(sensitive_data.private_key->n) >=
- BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED);
+ if (BN_num_bits(sensitive_data.private_key->n) <
+ BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) {
+ fatal("do_connection: private_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d",
+ BN_num_bits(sensitive_data.private_key->n),
+ BN_num_bits(sensitive_data.host_key->n),
+ SSH_KEY_BITS_RESERVED);
+ }
+
rsa_private_decrypt(session_key_int, session_key_int,
sensitive_data.private_key);
rsa_private_decrypt(session_key_int, session_key_int,
else
{
/* Host key has bigger modulus (or they are equal). */
- assert(BN_num_bits(sensitive_data.host_key->n) >=
- BN_num_bits(sensitive_data.private_key->n) +
- SSH_KEY_BITS_RESERVED);
+ if (BN_num_bits(sensitive_data.host_key->n) <
+ BN_num_bits(sensitive_data.private_key->n) + SSH_KEY_BITS_RESERVED) {
+ fatal("do_connection: host_key %d < private_key %d + SSH_KEY_BITS_RESERVED %d",
+ BN_num_bits(sensitive_data.host_key->n),
+ BN_num_bits(sensitive_data.private_key->n),
+ SSH_KEY_BITS_RESERVED);
+ }
rsa_private_decrypt(session_key_int, session_key_int,
sensitive_data.host_key);
rsa_private_decrypt(session_key_int, session_key_int,
/* Compute session id for this session. */
compute_session_id(session_id, check_bytes,
- BN_num_bits(sensitive_data.host_key->n),
sensitive_data.host_key->n,
- BN_num_bits(sensitive_data.private_key->n),
sensitive_data.private_key->n);
/* Extract session key from the decrypted integer. The key is in the
least significant 256 bits of the integer; the first byte of the
key is in the highest bits. */
BN_mask_bits(session_key_int, sizeof(session_key) * 8);
- assert(BN_num_bytes(session_key_int) == sizeof(session_key));
- BN_bn2bin(session_key_int, session_key);
+ len = BN_num_bytes(session_key_int);
+ if (len < 0 || len > sizeof(session_key))
+ fatal("do_connection: bad len: session_key_int %d > sizeof(session_key) %d",
+ len, sizeof(session_key));
+ memset(session_key, 0, sizeof(session_key));
+ BN_bn2bin(session_key_int, session_key + sizeof(session_key) - len);
/* Xor the first 16 bytes of the session key with the session id. */
for (i = 0; i < 16; i++)
/* Set the session key. From this on all communications will be
encrypted. */
- packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH,
- cipher_type, 0);
+ packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, cipher_type);
/* Destroy our copy of the session key. It is no longer needed. */
memset(session_key, 0, sizeof(session_key));
setproctitle("%s", user);
/* Do the authentication. */
- do_authentication(user, privileged_port);
+ do_authentication(user);
}
/* Check if the user is allowed to log in via ssh. If user is listed in
/* Performs authentication of an incoming connection. Session key has already
been exchanged and encryption is enabled. User is the user name to log
- in as (received from the clinet). Privileged_port is true if the
- connection comes from a privileged port (used for .rhosts authentication).*/
-
-#define MAX_AUTH_FAILURES 5
+ in as (received from the client). */
void
-do_authentication(char *user, int privileged_port)
+do_authentication(char *user)
{
- int type;
- int authenticated = 0;
- int authentication_failures = 0;
- char *password = NULL;
struct passwd *pw, pwcopy;
- char *client_user = NULL;
- unsigned int client_host_key_bits;
- BIGNUM *client_host_key_e, *client_host_key_n;
-#ifdef HAVE_LIBPAM
- int pam_retval;
-#endif /* HAVE_LIBPAM */
-
+
#ifdef AFS
/* If machine has AFS, set process authentication group. */
if (k_hasafs()) {
/* Verify that the user is a valid user. */
pw = getpwnam(user);
if (!pw || !allowed_user(pw))
- eat_packets_and_disconnect(user);
-
+ do_fake_authloop(user);
+
/* Take a copy of the returned structure. */
memset(&pwcopy, 0, sizeof(pwcopy));
pwcopy.pw_name = xstrdup(pw->pw_name);
pw = &pwcopy;
#ifdef HAVE_LIBPAM
- debug("Starting up PAM with username \"%.200s\"", pw->pw_name);
- pam_retval = pam_start("sshd", pw->pw_name, &conv, (pam_handle_t**)&pamh);
- if (pam_retval != PAM_SUCCESS)
{
- log("PAM initialisation failed: %.200s", pam_strerror((pam_handle_t *)pamh, pam_retval));
- eat_packets_and_disconnect(user);
+ int pam_retval;
+
+ debug("Starting up PAM with username \"%.200s\"", pw->pw_name);
+
+ pam_retval = pam_start("sshd", pw->pw_name, &conv, (pam_handle_t**)&pamh);
+ if (pam_retval != PAM_SUCCESS)
+ fatal("PAM initialisation failed: %.200s", pam_strerror((pam_handle_t *)pamh, pam_retval));
+
+ fatal_add_cleanup(&pam_cleanup_proc, NULL);
}
- fatal_add_cleanup(&pam_cleanup_proc, NULL);
#endif
/* If we are not running as root, the user must have the same uid as the
{
/* Authentication with empty password succeeded. */
debug("Login for user %.100s accepted without authentication.", user);
- /* authentication_type = SSH_AUTH_PASSWORD; */
- authenticated = 1;
- /* Success packet will be sent after loop below. */
+ } else {
+ /* Loop until the user has been authenticated or the connection is closed,
+ do_authloop() returns only if authentication is successfull */
+ do_authloop(pw);
}
- else
+
+ /* XXX log unified auth message */
+
+ /* Check if the user is logging in as root and root logins are disallowed. */
+ if (pw->pw_uid == 0 && !options.permit_root_login)
{
- /* Indicate that authentication is needed. */
- packet_start(SSH_SMSG_FAILURE);
- packet_send();
- packet_write_wait();
+ if (forced_command)
+ log("Root login accepted for forced command.");
+ else
+ packet_disconnect("ROOT LOGIN REFUSED FROM %.200s",
+ get_canonical_hostname());
}
- /* Loop until the user has been authenticated or the connection is closed. */
- while (!authenticated)
- {
- int plen;
- /* Get a packet from the client. */
- type = packet_read(&plen);
-
- /* Process the packet. */
- switch (type)
- {
+ /* The user has been authenticated and accepted. */
+ packet_start(SSH_SMSG_SUCCESS);
+ packet_send();
+ packet_write_wait();
-#ifdef AFS
- case SSH_CMSG_HAVE_KERBEROS_TGT:
- if (!options.kerberos_tgt_passing)
- {
- /* packet_get_all(); */
- log("Kerberos tgt passing disabled.");
- break;
- }
- else {
- /* Accept Kerberos tgt. */
- int dlen;
- char *tgt = packet_get_string(&dlen);
- packet_integrity_check(plen, 4 + dlen, type);
- if (!auth_kerberos_tgt(pw, tgt))
- debug("Kerberos tgt REFUSED for %s", user);
- xfree(tgt);
- }
- continue;
+ /* Perform session preparation. */
+ do_authenticated(pw);
+}
- case SSH_CMSG_HAVE_AFS_TOKEN:
- if (!options.afs_token_passing || !k_hasafs()) {
+#define MAX_AUTH_FAILURES 5
+
+/* read packets and try to authenticate local user *pw.
+ return if authentication is successfull */
+void
+do_authloop(struct passwd *pw)
+{
+ int authentication_failures = 0;
+ unsigned int bits;
+ BIGNUM *client_host_key_e, *client_host_key_n;
+ BIGNUM *n;
+ char *client_user = NULL, *password = NULL;
+ int plen, dlen, nlen, ulen, elen;
+#ifdef HAVE_LIBPAM
+ int pam_retval;
+#endif /* HAVE_LIBPAM */
+
+ /* Indicate that authentication is needed. */
+ packet_start(SSH_SMSG_FAILURE);
+ packet_send();
+ packet_write_wait();
+
+ for (;;) {
+ int authenticated = 0;
+
+ /* Get a packet from the client. */
+ int type = packet_read(&plen);
+
+ /* Process the packet. */
+ switch (type)
+ {
+#ifdef AFS
+ case SSH_CMSG_HAVE_KERBEROS_TGT:
+ if (!options.kerberos_tgt_passing)
+ {
/* packet_get_all(); */
- log("AFS token passing disabled.");
+ log("Kerberos tgt passing disabled.");
break;
}
- else {
- /* Accept AFS token. */
- int dlen;
- char *token_string = packet_get_string(&dlen);
- packet_integrity_check(plen, 4 + dlen, type);
- if (!auth_afs_token(user, pw->pw_uid, token_string))
- debug("AFS token REFUSED for %s", user);
- xfree(token_string);
- continue;
- }
+ else {
+ /* Accept Kerberos tgt. */
+ char *tgt = packet_get_string(&dlen);
+ packet_integrity_check(plen, 4 + dlen, type);
+ if (!auth_kerberos_tgt(pw, tgt))
+ debug("Kerberos tgt REFUSED for %s", pw->pw_name);
+ xfree(tgt);
+ }
+ continue;
+
+ case SSH_CMSG_HAVE_AFS_TOKEN:
+ if (!options.afs_token_passing || !k_hasafs()) {
+ /* packet_get_all(); */
+ log("AFS token passing disabled.");
+ break;
+ }
+ else {
+ /* Accept AFS token. */
+ char *token_string = packet_get_string(&dlen);
+ packet_integrity_check(plen, 4 + dlen, type);
+ if (!auth_afs_token(pw, token_string))
+ debug("AFS token REFUSED for %s", pw->pw_name);
+ xfree(token_string);
+ }
+ continue;
#endif /* AFS */
-
-#ifdef KRB4
- case SSH_CMSG_AUTH_KERBEROS:
- if (!options.kerberos_authentication)
- {
- /* packet_get_all(); */
- log("Kerberos authentication disabled.");
- break;
- }
- else {
- /* Try Kerberos v4 authentication. */
- KTEXT_ST auth;
- char *tkt_user = NULL;
- char *kdata = packet_get_string((unsigned int *)&auth.length);
- packet_integrity_check(plen, 4 + auth.length, type);
-
- if (auth.length < MAX_KTXT_LEN)
- memcpy(auth.dat, kdata, auth.length);
- xfree(kdata);
- if (auth_krb4(user, &auth, &tkt_user)) {
- /* Client has successfully authenticated to us. */
- log("Kerberos authentication accepted %s for account "
- "%s from %s", tkt_user, user, get_canonical_hostname());
- /* authentication_type = SSH_AUTH_KERBEROS; */
- authenticated = 1;
- xfree(tkt_user);
- }
- else {
- log("Kerberos authentication failed for account "
- "%s from %s", user, get_canonical_hostname());
- }
+#ifdef KRB4
+ case SSH_CMSG_AUTH_KERBEROS:
+ if (!options.kerberos_authentication)
+ {
+ /* packet_get_all(); */
+ log("Kerberos authentication disabled.");
+ break;
}
- break;
-#endif /* KRB4 */
+ else {
+ /* Try Kerberos v4 authentication. */
+ KTEXT_ST auth;
+ char *tkt_user = NULL;
+ char *kdata = packet_get_string((unsigned int *)&auth.length);
+ packet_integrity_check(plen, 4 + auth.length, type);
+
+ if (auth.length < MAX_KTXT_LEN)
+ memcpy(auth.dat, kdata, auth.length);
+ xfree(kdata);
- case SSH_CMSG_AUTH_RHOSTS:
- if (!options.rhosts_authentication)
- {
- log("Rhosts authentication disabled.");
- break;
- }
-
- /* Rhosts authentication (also uses /etc/hosts.equiv). */
- if (!privileged_port)
- {
- log("Rhosts authentication not available for connections from unprivileged port.");
- break;
- }
-
- /* Get client user name. Note that we just have to trust the client;
- this is one reason why rhosts authentication is insecure.
- (Another is IP-spoofing on a local network.) */
+ authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user);
+
+ log("Kerberos authentication %s%s for account %s from %s",
+ authenticated ? "accepted " : "failed",
+ tkt_user != NULL ? tkt_user : "",
+ pw->pw_name, get_canonical_hostname());
+ if (authenticated)
+ xfree(tkt_user);
+ }
+ break;
+#endif /* KRB4 */
+
+ case SSH_CMSG_AUTH_RHOSTS:
+ if (!options.rhosts_authentication)
{
- int dlen;
- client_user = packet_get_string(&dlen);
- packet_integrity_check(plen, 4 + dlen, type);
+ log("Rhosts authentication disabled.");
+ break;
}
+
+ /* Get client user name. Note that we just have to trust the client;
+ this is one reason why rhosts authentication is insecure.
+ (Another is IP-spoofing on a local network.) */
+ client_user = packet_get_string(&dlen);
+ packet_integrity_check(plen, 4 + dlen, type);
+
+ /* Try to authenticate using /etc/hosts.equiv and .rhosts. */
+ authenticated = auth_rhosts(pw, client_user);
- /* Try to authenticate using /etc/hosts.equiv and .rhosts. */
- if (auth_rhosts(pw, client_user, options.ignore_rhosts,
- options.strict_modes))
- {
- /* Authentication accepted. */
- log("Rhosts authentication accepted for %.100s, remote %.100s on %.700s.",
- user, client_user, get_canonical_hostname());
- authenticated = 1;
+ log("Rhosts authentication %s for %.100s, remote %.100s on %.700s.",
+ authenticated ? "accepted" : "failed",
+ pw->pw_name, client_user, get_canonical_hostname());
#ifndef HAVE_LIBPAM
- xfree(client_user);
+ xfree(client_user);
#endif /* HAVE_LIBPAM */
- break;
- }
- log("Rhosts authentication failed for %.100s, remote %.100s.",
- user, client_user);
-#ifndef HAVE_LIBPAM
- xfree(client_user);
-#endif /* HAVE_LIBPAM */
- break;
-
- case SSH_CMSG_AUTH_RHOSTS_RSA:
- if (!options.rhosts_rsa_authentication)
- {
- log("Rhosts with RSA authentication disabled.");
- break;
- }
-
- /* Rhosts authentication (also uses /etc/hosts.equiv) with RSA
- host authentication. */
- if (!privileged_port)
- {
- log("Rhosts authentication not available for connections from unprivileged port.");
- break;
- }
-
+ break;
+
+ case SSH_CMSG_AUTH_RHOSTS_RSA:
+ if (!options.rhosts_rsa_authentication)
{
- int ulen, elen, nlen;
- /* Get client user name. Note that we just have to trust
- the client; root on the client machine can claim to be
- any user. */
- client_user = packet_get_string(&ulen);
-
- /* Get the client host key. */
- client_host_key_e = BN_new();
- client_host_key_n = BN_new();
- client_host_key_bits = packet_get_int();
- packet_get_bignum(client_host_key_e, &elen);
- packet_get_bignum(client_host_key_n, &nlen);
-
- packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type);
+ log("Rhosts with RSA authentication disabled.");
+ break;
}
-
- /* Try to authenticate using /etc/hosts.equiv and .rhosts. */
- if (auth_rhosts_rsa(pw, client_user,
- client_host_key_bits, client_host_key_e,
- client_host_key_n, options.ignore_rhosts,
- options.strict_modes))
- {
- /* Authentication accepted. */
- authenticated = 1;
-#ifndef HAVE_LIBPAM
- xfree(client_user);
-#endif /* HAVE_LIBPAM */
- BN_clear_free(client_host_key_e);
- BN_clear_free(client_host_key_n);
- break;
- }
- log("Rhosts authentication failed for %.100s, remote %.100s.",
- user, client_user);
+
+ /* Get client user name. Note that we just have to trust
+ the client; root on the client machine can claim to be
+ any user. */
+ client_user = packet_get_string(&ulen);
+
+ /* Get the client host key. */
+ client_host_key_e = BN_new();
+ client_host_key_n = BN_new();
+ bits = packet_get_int();
+ packet_get_bignum(client_host_key_e, &elen);
+ packet_get_bignum(client_host_key_n, &nlen);
+
+ if (bits != BN_num_bits(client_host_key_n))
+ error("Warning: keysize mismatch for client_host_key: "
+ "actual %d, announced %d", BN_num_bits(client_host_key_n), bits);
+ packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type);
+
+ authenticated = auth_rhosts_rsa(pw, client_user,
+ client_host_key_e, client_host_key_n);
+ log("Rhosts authentication %s for %.100s, remote %.100s.",
+ authenticated ? "accepted" : "failed",
+ pw->pw_name, client_user);
#ifndef HAVE_LIBPAM
- xfree(client_user);
+ xfree(client_user);
#endif /* HAVE_LIBPAM */
- BN_clear_free(client_host_key_e);
- BN_clear_free(client_host_key_n);
- break;
-
- case SSH_CMSG_AUTH_RSA:
- if (!options.rsa_authentication)
- {
- log("RSA authentication disabled.");
- break;
- }
-
- /* RSA authentication requested. */
+ BN_clear_free(client_host_key_e);
+ BN_clear_free(client_host_key_n);
+ break;
+
+ case SSH_CMSG_AUTH_RSA:
+ if (!options.rsa_authentication)
{
- int nlen;
- BIGNUM *n;
- n = BN_new();
- packet_get_bignum(n, &nlen);
-
- packet_integrity_check(plen, nlen, type);
-
- if (auth_rsa(pw, n, options.strict_modes))
- {
- /* Successful authentication. */
- BN_clear_free(n);
- log("RSA authentication for %.100s accepted.", user);
- authenticated = 1;
- break;
- }
- BN_clear_free(n);
- log("RSA authentication for %.100s failed.", user);
+ log("RSA authentication disabled.");
+ break;
}
- break;
-
- case SSH_CMSG_AUTH_PASSWORD:
- if (!options.password_authentication)
- {
- log("Password authentication disabled.");
- break;
- }
-
- /* Password authentication requested. */
- /* Read user password. It is in plain text, but was transmitted
- over the encrypted channel so it is not visible to an outside
- observer. */
+
+ /* RSA authentication requested. */
+ n = BN_new();
+ packet_get_bignum(n, &nlen);
+ packet_integrity_check(plen, nlen, type);
+
+ authenticated = auth_rsa(pw, n);
+ log("RSA authentication %s for %.100s.",
+ authenticated ? "accepted" : "failed",
+ pw->pw_name);
+ BN_clear_free(n);
+ break;
+
+ case SSH_CMSG_AUTH_PASSWORD:
+ if (!options.password_authentication)
{
- int passw_len;
- password = packet_get_string(&passw_len);
- packet_integrity_check(plen, 4 + passw_len, type);
+ log("Password authentication disabled.");
+ break;
}
-
+
+ /* Read user password. It is in plain text, but was transmitted
+ over the encrypted channel so it is not visible to an outside
+ observer. */
+ password = packet_get_string(&dlen);
+ packet_integrity_check(plen, 4 + dlen, type);
+
#ifdef HAVE_LIBPAM
- pampasswd = password;
-
- pam_retval = pam_authenticate((pam_handle_t *)pamh, 0);
- if (pam_retval == PAM_SUCCESS)
- {
- log("PAM Password authentication accepted for \"%.100s\"", user);
- authenticated = 1;
- break;
- } else
- {
- log("PAM Password authentication for \"%.100s\" failed: %s",
- user, pam_strerror((pam_handle_t *)pamh, pam_retval));
- break;
- }
+ /* Do PAM auth with password */
+ pampasswd = password;
+ pam_retval = pam_authenticate((pam_handle_t *)pamh, 0);
+ if (pam_retval == PAM_SUCCESS)
+ {
+ log("PAM Password authentication accepted for user \"%.100s\"", pw->pw_name);
+ authenticated = 1;
+ break;
+ }
+
+ log("PAM Password authentication for \"%.100s\" failed: %s",
+ pw->pw_name, pam_strerror((pam_handle_t *)pamh, pam_retval));
+ break;
#else /* HAVE_LIBPAM */
- /* Try authentication with the password. */
- if (auth_password(pw, password))
- {
- /* Successful authentication. */
- /* Clear the password from memory. */
- memset(password, 0, strlen(password));
- xfree(password);
- log("Password authentication for %.100s accepted.", user);
- authenticated = 1;
- break;
- }
- log("Password authentication for %.100s failed.", user);
- memset(password, 0, strlen(password));
- xfree(password);
- break;
+ /* Try authentication with the password. */
+ authenticated = auth_password(pw, password);
+ log("Password authentication %s for %.100s.",
+ authenticated ? "accepted" : "failed",
+ pw->pw_name);
+
+ memset(password, 0, strlen(password));
+ xfree(password);
+ break;
#endif /* HAVE_LIBPAM */
-
- case SSH_CMSG_AUTH_TIS:
- /* TIS Authentication is unsupported */
- log("TIS authentication disabled.");
- break;
-
- default:
- /* Any unknown messages will be ignored (and failure returned)
- during authentication. */
- log("Unknown message during authentication: type %d", type);
- break; /* Respond with a failure message. */
- }
- /* If successfully authenticated, break out of loop. */
- if (authenticated)
+
+ case SSH_CMSG_AUTH_TIS:
+ /* TIS Authentication is unsupported */
+ log("TIS authentication disabled.");
break;
-
- /* Send a message indicating that the authentication attempt failed. */
- packet_start(SSH_SMSG_FAILURE);
- packet_send();
- packet_write_wait();
-
- if (++authentication_failures >= MAX_AUTH_FAILURES) {
- packet_disconnect("Too many authentication failures for %.100s from %.200s",
- pw->pw_name, get_canonical_hostname());
+
+ default:
+ /* Any unknown messages will be ignored (and failure returned)
+ during authentication. */
+ log("Unknown message during authentication: type %d", type);
+ break; /* Respond with a failure message. */
}
- }
- /* Check if the user is logging in as root and root logins are disallowed. */
- if (pw->pw_uid == 0 && !options.permit_root_login)
- {
- if (forced_command)
- log("Root login accepted for forced command.", forced_command);
- else
- packet_disconnect("ROOT LOGIN REFUSED FROM %.200s",
- get_canonical_hostname());
- }
+ if (authenticated)
+ break;
+ if (++authentication_failures >= MAX_AUTH_FAILURES)
+ packet_disconnect("Too many authentication failures for %.100s from %.200s",
+ pw->pw_name, get_canonical_hostname());
+ /* Send a message indicating that the authentication attempt failed. */
+ packet_start(SSH_SMSG_FAILURE);
+ packet_send();
+ packet_write_wait();
+ }
#ifdef HAVE_LIBPAM
- do_pam_account_and_session(pw->pw_name, password, client_user, get_canonical_hostname());
+ do_pam_account_and_session(pw->pw_name, client_user, get_canonical_hostname());
/* Clean up */
if (client_user != NULL)
xfree(password);
}
#endif /* HAVE_LIBPAM */
-
- /* The user has been authenticated and accepted. */
- packet_start(SSH_SMSG_SUCCESS);
- packet_send();
- packet_write_wait();
-
- /* Perform session preparation. */
- do_authenticated(pw);
}
-/* Read authentication messages, but return only failures until */
-/* max auth attempts exceeded, then disconnect */
-void eat_packets_and_disconnect(const char *user)
+/* The user does not exist or access is denied,
+ but fake indication that authentication is needed. */
+void
+do_fake_authloop(char *user)
{
int authentication_failures = 0;
-
+
+ /* Indicate that authentication is needed. */
packet_start(SSH_SMSG_FAILURE);
packet_send();
packet_write_wait();
/* Keep reading packets, and always respond with a failure. This is to
avoid disclosing whether such a user really exists. */
- while(1)
- {
- /* Read a packet. This will not return if the client disconnects. */
- int plen;
-#ifndef SKEY
- (void) packet_read(&plen);
-#else /* SKEY */
- int type = packet_read(&plen);
- int passw_len;
- char *password, *skeyinfo;
- if (options.password_authentication &&
- options.skey_authentication == 1 &&
- type == SSH_CMSG_AUTH_PASSWORD &&
- (password = packet_get_string(&passw_len)) != NULL &&
- passw_len == 5 &&
- strncasecmp(password, "s/key", 5) == 0 &&
- (skeyinfo = skey_fake_keyinfo(user)) != NULL )
+ for (;;)
{
- /* Send a fake s/key challenge. */
- packet_send_debug(skeyinfo);
- }
-#endif /* SKEY */
- /* Send failure. This should be indistinguishable from a failed
- authentication. */
- packet_start(SSH_SMSG_FAILURE);
- packet_send();
- packet_write_wait();
- if (++authentication_failures >= MAX_AUTH_FAILURES)
- {
- packet_disconnect("Too many authentication failures for %.100s from %.200s",
- user, get_canonical_hostname());
+ /* Read a packet. This will not return if the client disconnects. */
+ int plen;
+ int type = packet_read(&plen);
+#ifdef SKEY
+ int passw_len;
+ char *password, *skeyinfo;
+ if (options.password_authentication &&
+ options.skey_authentication == 1 &&
+ type == SSH_CMSG_AUTH_PASSWORD &&
+ (password = packet_get_string(&passw_len)) != NULL &&
+ passw_len == 5 &&
+ strncasecmp(password, "s/key", 5) == 0 &&
+ (skeyinfo = skey_fake_keyinfo(user)) != NULL ){
+ /* Send a fake s/key challenge. */
+ packet_send_debug(skeyinfo);
+ }
+#endif
+ if (++authentication_failures >= MAX_AUTH_FAILURES)
+ packet_disconnect("Too many authentication failures for %.100s from %.200s",
+ user, get_canonical_hostname());
+ /* Send failure. This should be indistinguishable from a failed
+ authentication. */
+ packet_start(SSH_SMSG_FAILURE);
+ packet_send();
+ packet_write_wait();
}
- }
/*NOTREACHED*/
abort();
}
+
+/* Remove local Xauthority file. */
+static void
+xauthfile_cleanup_proc(void *ignore)
+{
+ debug("xauthfile_cleanup_proc called");
+
+ if (xauthfile != NULL) {
+ unlink(xauthfile);
+ xfree(xauthfile);
+ xauthfile = NULL;
+ }
+}
+
/* Prepares for an interactive session. This is called after the user has
been successfully authenticated. During this message exchange, pseudo
terminals are allocated, X11, TCP/IP, and authentication agent forwardings
if ((xauthfd = mkstemp(xauthfile)) != -1) {
fchown(xauthfd, pw->pw_uid, pw->pw_gid);
close(xauthfd);
+ fatal_add_cleanup(xauthfile_cleanup_proc, NULL);
}
else {
xfree(xauthfile);
if ((pid = fork()) == 0)
{
/* Child. Reinitialize the log since the pid has changed. */
- log_init(av0, debug_flag && !inetd_flag, debug_flag,
- options.quiet_mode, options.log_facility);
+ log_init(av0, options.log_level, options.log_facility, log_stderr);
/* Create a new session and process group since the 4.4BSD setlogin()
affects the entire process group. */
debug("pty_cleanup_proc called");
-#if defined(KRB4)
- /* Destroy user's ticket cache file. */
- (void) dest_tkt();
-#endif /* KRB4 */
-
/* Record that the user has logged out. */
record_logout(cu->pid, cu->ttyname);
pid = getpid();
/* Child. Reinitialize the log because the pid has changed. */
- log_init(av0, debug_flag && !inetd_flag, debug_flag, options.quiet_mode,
- options.log_facility);
+ log_init(av0, options.log_level, options.log_facility, log_stderr);
/* Close the master side of the pseudo tty. */
close(ptyfd);
{
fromlen = sizeof(from);
if (getpeername(packet_get_connection_in(),
- (struct sockaddr *)&from, &fromlen) < 0)
- fatal("getpeername: %.100s", strerror(errno));
+ (struct sockaddr *)&from, &fromlen) < 0) {
+ debug("getpeername: %.100s", strerror(errno));
+ fatal_cleanup();
+ }
}
/* Record that there was a login on that terminal. */
/* Check if .hushlogin exists. */
snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir);
quiet_login = stat(line, &st) >= 0;
-
+
+#ifdef HAVE_LIBPAM
+ /* output the results of the pamconv() */
+ if (!quiet_login && pamconv_msg != NULL)
+ fprintf(stderr, pamconv_msg);
+#endif
+
/* If the user has logged in before, display the time of last login.
However, don't display anything extra if a command has been
specified (so that ssh can be used to execute commands on a remote
struct stat st;
char *argv[10];
+#ifndef HAVE_LIBPAM /* pam_nologin handles this */
/* Check /etc/nologin. */
f = fopen("/etc/nologin", "r");
if (f)
if (pw->pw_uid != 0)
exit(254);
}
+#endif /* HAVE_LIBPAM */
+
+#ifdef HAVE_SETLOGIN
+ /* Set login name in the kernel. */
+ if (setlogin(pw->pw_name) < 0)
+ error("setlogin failed: %s", strerror(errno));
+#endif /* HAVE_SETLOGIN */
/* Set uid, gid, and groups. */
/* Login(1) does this as well, and it needs uid 0 for the "-h" switch,
child_set_env(&env, &envsize, "DISPLAY", display);
#ifdef KRB4
- if (ticket)
- child_set_env(&env, &envsize, "KRBTKFILE", ticket);
+ {
+ extern char *ticket;
+
+ if (ticket)
+ child_set_env(&env, &envsize, "KRBTKFILE", ticket);
+ }
#endif /* KRB4 */
#ifdef HAVE_LIBPAM
} else {
/* Launch login(1). */
- execl("/usr/bin/login", "login", "-h", get_remote_ipaddr(), "-p", "-f", "--", pw->pw_name, NULL);
+ execl(LOGIN_PROGRAM, "login", "-h", get_remote_ipaddr(), "-p", "-f", "--", pw->pw_name, NULL);
/* Login couldn't be executed, die. */