- Merged more OpenBSD CVS changes:

[auth-krb4.c]
          - disconnect if getpeername() fails
          - missing xfree(*client)
        [canohost.c]
          - disconnect if getpeername() fails
          - fix comment: we _do_ disconnect if ip-options are set
        [sshd.c]
          - disconnect if getpeername() fails
          - move checking of remote port to central place
        [auth-rhosts.c] move checking of remote port to central place
        [log-server.c] avoid extra fd per sshd, from millert@
        [readconf.c] print _all_ bad config-options in ssh(1), too
        [readconf.h] print _all_ bad config-options in ssh(1), too
        [ssh.c] print _all_ bad config-options in ssh(1), too
        [sshconnect.c] disconnect if getpeername() fails
 - OpenBSD's changes to sshd.c broke the PAM stuff, re-merged it.
This commit is contained in:
Damien Miller 1999-11-15 15:25:10 +11:00
parent cedfecc99e
commit 2ccf661cbe
10 changed files with 396 additions and 437 deletions

View File

@ -5,6 +5,23 @@
- Changed to ssh-add.c broke askpass support. Revised it to be a little more
modular.
- Revised autoconf support for enabling/disabling askpass support.
- Merged more OpenBSD CVS changes:
[auth-krb4.c]
- disconnect if getpeername() fails
- missing xfree(*client)
[canohost.c]
- disconnect if getpeername() fails
- fix comment: we _do_ disconnect if ip-options are set
[sshd.c]
- disconnect if getpeername() fails
- move checking of remote port to central place
[auth-rhosts.c] move checking of remote port to central place
[log-server.c] avoid extra fd per sshd, from millert@
[readconf.c] print _all_ bad config-options in ssh(1), too
[readconf.h] print _all_ bad config-options in ssh(1), too
[ssh.c] print _all_ bad config-options in ssh(1), too
[sshconnect.c] disconnect if getpeername() fails
- OpenBSD's changes to sshd.c broke the PAM stuff, re-merged it.
19991114
- Solaris compilation fixes (still imcomplete)

View File

@ -6,7 +6,7 @@
Kerberos v4 authentication and ticket-passing routines.
$Id: auth-krb4.c,v 1.3 1999/11/11 06:57:39 damien Exp $
$Id: auth-krb4.c,v 1.4 1999/11/15 04:25:10 damien Exp $
*/
#include "includes.h"
@ -89,8 +89,10 @@ int auth_krb4(const char *server_user, KTEXT auth, char **client)
debug("getsockname failed: %.100s", strerror(errno));
r = sizeof(foreign);
memset(&foreign, 0, sizeof(foreign));
if (getpeername(s, (struct sockaddr *)&foreign, &r) < 0)
if (getpeername(s, (struct sockaddr *)&foreign, &r) < 0) {
debug("getpeername failed: %.100s", strerror(errno));
fatal_cleanup();
}
instance[0] = '*'; instance[1] = 0;
@ -110,6 +112,7 @@ int auth_krb4(const char *server_user, KTEXT auth, char **client)
packet_send_debug("Kerberos V4 .klogin authorization failed!");
log("Kerberos V4 .klogin authorization failed for %s to account %s",
*client, server_user);
xfree(*client);
return 0;
}
/* Increment the checksum, and return it encrypted with the session key. */

View File

@ -16,7 +16,7 @@ the login based on rhosts authentication. This file also processes
*/
#include "includes.h"
RCSID("$Id: auth-rhosts.c,v 1.2 1999/11/12 04:19:27 damien Exp $");
RCSID("$Id: auth-rhosts.c,v 1.3 1999/11/15 04:25:10 damien Exp $");
#include "packet.h"
#include "ssh.h"
@ -161,7 +161,6 @@ int auth_rhosts(struct passwd *pw, const char *client_user)
extern ServerOptions options;
char buf[1024];
const char *hostname, *ipaddr;
int port;
struct stat st;
static const char *rhosts_files[] = { ".shosts", ".rhosts", NULL };
unsigned int rhosts_file_index;
@ -190,21 +189,6 @@ int auth_rhosts(struct passwd *pw, const char *client_user)
/* Get the name, address, and port of the remote host. */
hostname = get_canonical_hostname();
ipaddr = get_remote_ipaddr();
port = get_remote_port();
/* Check that the connection comes from a privileged port.
Rhosts authentication only makes sense for priviledged programs.
Of course, if the intruder has root access on his local machine,
he can connect from any port. So do not use .rhosts
authentication from machines that you do not trust. */
if (port >= IPPORT_RESERVED ||
port < IPPORT_RESERVED / 2)
{
log("Connection from %.100s from nonpriviledged port %d",
hostname, port);
packet_send_debug("Your ssh client is not running as root.");
return 0;
}
/* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */
if (pw->pw_uid != 0)

View File

@ -14,7 +14,7 @@ Functions for returning the canonical host name of the remote site.
*/
#include "includes.h"
RCSID("$Id: canohost.c,v 1.1 1999/10/27 03:42:43 damien Exp $");
RCSID("$Id: canohost.c,v 1.2 1999/11/15 04:25:10 damien Exp $");
#include "packet.h"
#include "xmalloc.h"
@ -35,9 +35,8 @@ char *get_remote_hostname(int socket)
memset(&from, 0, sizeof(from));
if (getpeername(socket, (struct sockaddr *)&from, &fromlen) < 0)
{
error("getpeername failed: %.100s", strerror(errno));
strlcpy(name, "UNKNOWN", sizeof name);
goto check_ip_options;
debug("getpeername failed: %.100s", strerror(errno));
fatal_cleanup();
}
/* Map the IP address to a host name. */
@ -99,7 +98,7 @@ char *get_remote_hostname(int socket)
check_ip_options:
/* If IP options are supported, make sure there are none (log and clear
/* If IP options are supported, make sure there are none (log and disconnect
them if any are found). Basically we are worried about source routing;
it can be used to pretend you are somebody (ip-address) you are not.
That itself may be "almost acceptable" under certain circumstances,
@ -184,8 +183,8 @@ const char *get_remote_ipaddr()
memset(&from, 0, sizeof(from));
if (getpeername(socket, (struct sockaddr *)&from, &fromlen) < 0)
{
error("getpeername failed: %.100s", strerror(errno));
return NULL;
debug("getpeername failed: %.100s", strerror(errno));
fatal_cleanup();
}
/* Get the IP address in ascii. */
@ -207,8 +206,8 @@ int get_peer_port(int sock)
memset(&from, 0, sizeof(from));
if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0)
{
error("getpeername failed: %.100s", strerror(errno));
return 0;
debug("getpeername failed: %.100s", strerror(errno));
fatal_cleanup();
}
/* Return port number. */

View File

@ -15,7 +15,7 @@ to the system log.
*/
#include "includes.h"
RCSID("$Id: log-server.c,v 1.2 1999/11/11 06:57:39 damien Exp $");
RCSID("$Id: log-server.c,v 1.3 1999/11/15 04:25:10 damien Exp $");
#include <syslog.h>
#include "packet.h"
@ -24,6 +24,7 @@ RCSID("$Id: log-server.c,v 1.2 1999/11/11 06:57:39 damien Exp $");
static LogLevel log_level = SYSLOG_LEVEL_INFO;
static int log_on_stderr = 0;
static int log_facility = LOG_AUTH;
/* Initialize the log.
av0 program name (should be argv[0])
@ -33,7 +34,6 @@ static int log_on_stderr = 0;
void log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
{
int log_facility;
switch (level)
{
@ -93,8 +93,6 @@ void log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
}
log_on_stderr = on_stderr;
closelog(); /* Close any previous log. */
openlog(av0, LOG_PID, log_facility);
}
#define MSGBUFSIZE 1024
@ -106,6 +104,7 @@ do_log(LogLevel level, const char *fmt, va_list args)
char fmtbuf[MSGBUFSIZE];
char *txt = NULL;
int pri = LOG_INFO;
extern char *__progname;
if (level > log_level)
return;
@ -143,5 +142,7 @@ do_log(LogLevel level, const char *fmt, va_list args)
}
if (log_on_stderr)
fprintf(stderr, "%s\n", msgbuf);
openlog(__progname, LOG_PID, log_facility);
syslog(pri, "%.500s", msgbuf);
closelog();
}

View File

@ -14,7 +14,7 @@ Functions for reading the configuration files.
*/
#include "includes.h"
RCSID("$Id: readconf.c,v 1.2 1999/11/11 06:57:39 damien Exp $");
RCSID("$Id: readconf.c,v 1.3 1999/11/15 04:25:10 damien Exp $");
#include "ssh.h"
#include "cipher.h"
@ -88,6 +88,7 @@ RCSID("$Id: readconf.c,v 1.2 1999/11/11 06:57:39 damien Exp $");
typedef enum
{
oBadOption,
oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication,
oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh,
#ifdef KRB4
@ -222,16 +223,16 @@ static OpCodes parse_token(const char *cp, const char *filename, int linenum)
if (strcmp(cp, keywords[i].name) == 0)
return keywords[i].opcode;
fatal("%.200s line %d: Bad configuration option.",
filename, linenum);
/*NOTREACHED*/
return 0;
fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
filename, linenum, cp);
return oBadOption;
}
/* Processes a single option line as used in the configuration files.
This only sets those values that have not already been set. */
void process_config_line(Options *options, const char *host,
int
process_config_line(Options *options, const char *host,
char *line, const char *filename, int linenum,
int *activep)
{
@ -241,7 +242,7 @@ void process_config_line(Options *options, const char *host,
/* Skip leading whitespace. */
cp = line + strspn(line, WHITESPACE);
if (!*cp || *cp == '\n' || *cp == '#')
return;
return 0;
/* Get the keyword. (Each line is supposed to begin with a keyword). */
cp = strtok(cp, WHITESPACE);
@ -256,7 +257,9 @@ void process_config_line(Options *options, const char *host,
switch (opcode)
{
case oBadOption:
return -1; /* don't panic, but count bad options */
/*NOTREACHED*/
case oForwardAgent:
intptr = &options->forward_agent;
parse_flag:
@ -426,7 +429,7 @@ void process_config_line(Options *options, const char *host,
*charptr = string;
else
xfree(string);
return;
return 0;
case oPort:
intptr = &options->port;
@ -533,7 +536,7 @@ void process_config_line(Options *options, const char *host,
break;
}
/* Avoid garbage check below, as strtok already returned NULL. */
return;
return 0;
case oEscapeChar:
intptr = &options->escape_char;
@ -561,13 +564,14 @@ void process_config_line(Options *options, const char *host,
break;
default:
fatal("parse_config_file: Unimplemented opcode %d", opcode);
fatal("process_config_line: Unimplemented opcode %d", opcode);
}
/* Check that there is no garbage at end of line. */
if (strtok(NULL, WHITESPACE) != NULL)
fatal("%.200s line %d: garbage at end of line.",
filename, linenum);
return 0;
}
@ -580,6 +584,7 @@ void read_config_file(const char *filename, const char *host, Options *options)
FILE *f;
char line[1024];
int active, linenum;
int bad_options = 0;
/* Open the file. */
f = fopen(filename, "r");
@ -596,10 +601,13 @@ void read_config_file(const char *filename, const char *host, Options *options)
{
/* Update line number counter. */
linenum++;
process_config_line(options, host, line, filename, linenum, &active);
if (process_config_line(options, host, line, filename, linenum, &active) != 0)
bad_options++;
}
fclose(f);
if (bad_options > 0)
fatal("%s: terminating, %d bad configuration options\n",
filename, bad_options);
}
/* Initializes options to special values that indicate that they have not

View File

@ -13,7 +13,7 @@ Functions for reading the configuration file.
*/
/* RCSID("$Id: readconf.h,v 1.2 1999/11/11 06:57:39 damien Exp $"); */
/* RCSID("$Id: readconf.h,v 1.3 1999/11/15 04:25:10 damien Exp $"); */
#ifndef READCONF_H
#define READCONF_H
@ -92,8 +92,9 @@ void initialize_options(Options *options);
void fill_default_options(Options *options);
/* Processes a single option line as used in the configuration files.
This only sets those values that have not already been set. */
void process_config_line(Options *options, const char *host,
This only sets those values that have not already been set.
Returns 0 for legal options */
int process_config_line(Options *options, const char *host,
char *line, const char *filename, int linenum,
int *activep);

7
ssh.c
View File

@ -18,7 +18,7 @@ Modified to work with SSL by Niels Provos <provos@citi.umich.edu> in Canada.
*/
#include "includes.h"
RCSID("$Id: ssh.c,v 1.7 1999/11/13 02:28:45 damien Exp $");
RCSID("$Id: ssh.c,v 1.8 1999/11/15 04:25:10 damien Exp $");
#include "xmalloc.h"
#include "ssh.h"
@ -383,8 +383,9 @@ main(int ac, char **av)
case 'o':
dummy = 1;
process_config_line(&options, host ? host : "", optarg,
"command-line", 0, &dummy);
if (process_config_line(&options, host ? host : "", optarg,
"command-line", 0, &dummy) != 0)
exit(1);
break;
default:

View File

@ -15,7 +15,7 @@ login (authentication) dialog.
*/
#include "includes.h"
RCSID("$Id: sshconnect.c,v 1.7 1999/11/12 23:51:58 damien Exp $");
RCSID("$Id: sshconnect.c,v 1.8 1999/11/15 04:25:10 damien Exp $");
#ifdef HAVE_OPENSSL
#include <openssl/bn.h>
@ -730,8 +730,10 @@ int try_kerberos_authentication()
r = sizeof(foreign);
memset(&foreign, 0, sizeof(foreign));
if (getpeername(packet_get_connection_in(),
(struct sockaddr *)&foreign, &r) < 0)
(struct sockaddr *)&foreign, &r) < 0) {
debug("getpeername failed: %s", strerror(errno));
fatal_cleanup();
}
/* Get server reply. */
type = packet_read(&plen);

711
sshd.c
View File

@ -18,7 +18,7 @@ agent connections.
*/
#include "includes.h"
RCSID("$Id: sshd.c,v 1.17 1999/11/12 04:19:27 damien Exp $");
RCSID("$Id: sshd.c,v 1.18 1999/11/15 04:25:10 damien Exp $");
#include "xmalloc.h"
#include "rsa.h"
@ -114,9 +114,10 @@ int received_sighup = 0;
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,
@ -128,11 +129,12 @@ void do_exec_no_pty(const char *command, struct passwd *pw,
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(const char *username,
const char *remote_user, const char *remote_host);
void pam_cleanup_proc(void *context);
static struct pam_conv conv = {
@ -228,7 +230,7 @@ void pam_cleanup_proc(void *context)
}
}
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(const char *username, const char *remote_user, const char *remote_host)
{
int pam_retval;
@ -239,7 +241,7 @@ void do_pam_account_and_session(const char *username, const char *password, cons
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);
}
}
@ -250,7 +252,7 @@ void do_pam_account_and_session(const char *username, const char *password, cons
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);
}
}
@ -258,14 +260,14 @@ void do_pam_account_and_session(const char *username, const char *password, cons
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 */
@ -375,6 +377,7 @@ main(int ac, char **av)
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;
@ -742,6 +745,8 @@ main(int ac, char **av)
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
{
@ -755,13 +760,11 @@ main(int ac, char **av)
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
@ -834,11 +837,23 @@ main(int ac, char **av)
}
}
/* 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. */
@ -879,7 +894,8 @@ main(int ac, char **av)
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, len;
BIGNUM *session_key_int;
@ -1071,7 +1087,7 @@ void do_connection(int privileged_port)
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
@ -1154,26 +1170,13 @@ allowed_user(struct passwd *pw)
/* 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()) {
@ -1185,8 +1188,8 @@ do_authentication(char *user, int privileged_port)
/* 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);
@ -1199,13 +1202,11 @@ do_authentication(char *user, int privileged_port)
#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);
}
fatal_add_cleanup(&pam_cleanup_proc, NULL);
if (pam_start("sshd", pw->pw_name, &conv, (pam_handle_t**)&pamh) != PAM_SUCCESS)
fatal("PAM initialisation failed: %.200s", pam_strerror((pam_handle_t *)pamh, pam_retval));
fatal_add_cleanup(&pam_cleanup_proc, NULL);
#endif
/* If we are not running as root, the user must have the same uid as the
@ -1224,300 +1225,13 @@ do_authentication(char *user, int privileged_port)
{
/* 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
{
/* Indicate that authentication is needed. */
packet_start(SSH_SMSG_FAILURE);
packet_send();
packet_write_wait();
} else {
/* Loop until the user has been authenticated or the connection is closed,
do_authloop() returns only if authentication is successfull */
do_authloop(pw);
}
/* 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)
{
#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;
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. */
int dlen;
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", user);
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());
}
}
break;
#endif /* KRB4 */
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.) */
{
int dlen;
client_user = packet_get_string(&dlen);
packet_integrity_check(plen, 4 + dlen, type);
}
/* Try to authenticate using /etc/hosts.equiv and .rhosts. */
if (auth_rhosts(pw, client_user))
{
/* Authentication accepted. */
log("Rhosts authentication accepted for %.100s, remote %.100s on %.700s.",
user, client_user, get_canonical_hostname());
authenticated = 1;
#ifndef HAVE_LIBPAM
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;
}
{
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);
}
if (auth_rhosts_rsa(pw, client_user,
client_host_key_bits, client_host_key_e, client_host_key_n))
{
/* 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);
#ifndef HAVE_LIBPAM
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. */
{
int nlen;
BIGNUM *n;
n = BN_new();
packet_get_bignum(n, &nlen);
packet_integrity_check(plen, nlen, type);
if (auth_rsa(pw, n))
{
/* 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);
}
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. */
{
int passw_len;
password = packet_get_string(&passw_len);
packet_integrity_check(plen, 4 + passw_len, 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;
}
#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;
#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)
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();
}
/* 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)
@ -1529,8 +1243,245 @@ do_authentication(char *user, int privileged_port)
get_canonical_hostname());
}
/* The user has been authenticated and accepted. */
packet_start(SSH_SMSG_SUCCESS);
packet_send();
packet_write_wait();
/* Perform session preparation. */
do_authenticated(pw);
}
#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 client_host_key_bits;
BIGNUM *client_host_key_e, *client_host_key_n;
BIGNUM *n;
char *client_user, *password;
int plen, dlen, nlen, ulen, elen;
/* 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("Kerberos tgt passing disabled.");
break;
}
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);
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)
{
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);
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);
#endif /* HAVE_LIBPAM */
break;
case SSH_CMSG_AUTH_RHOSTS_RSA:
if (!options.rhosts_rsa_authentication)
{
log("Rhosts with RSA authentication disabled.");
break;
}
/* 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);
authenticated = auth_rhosts_rsa(pw, client_user, client_host_key_bits,
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);
#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. */
n = BN_new();
packet_get_bignum(n, &nlen);
packet_integrity_check(plen, nlen, type);
authenticated = auth_rsa(pw, n);
BN_clear_free(n);
log("RSA authentication %s for %.100s.",
authenticated ? "accepted" : "failed",
pw->pw_name);
break;
case SSH_CMSG_AUTH_PASSWORD:
if (!options.password_authentication)
{
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
do_pam_account_and_session(pw->pw_name, password, client_user, get_canonical_hostname());
/* 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\"", user);
authenticated = 1;
break;
}
log("PAM Password authentication for \"%.100s\" failed: %s",
user, pam_strerror((pam_handle_t *)pamh, pam_retval));
break;
#else /* HAVE_LIBPAM */
/* Try authentication with the password. */
authenticated = auth_password(pw, password);
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 (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, client_user, get_canonical_hostname());
/* Clean up */
if (client_user != NULL)
@ -1542,65 +1493,55 @@ do_authentication(char *user, int privileged_port)
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);
/* 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();
}
#endif /* SKEY */
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)
@ -2075,8 +2016,10 @@ void do_exec_pty(const char *command, int ptyfd, int ttyfd,
{
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. */