From e7c0f9d591754e0c5512aa3cb5543dbb4e45605b Mon Sep 17 00:00:00 2001 From: damien Date: Mon, 15 Nov 1999 04:25:10 +0000 Subject: [PATCH] - 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. --- ChangeLog | 17 ++ auth-krb4.c | 5 +- auth-rhosts.c | 16 -- canohost.c | 15 +- log-server.c | 7 +- readconf.c | 32 ++- readconf.h | 5 +- ssh.c | 5 +- sshconnect.c | 4 +- sshd.c | 669 +++++++++++++++++++++++--------------------------- 10 files changed, 367 insertions(+), 408 deletions(-) diff --git a/ChangeLog b/ChangeLog index 52899434..d1c75cce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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) diff --git a/auth-krb4.c b/auth-krb4.c index fc26a708..7bb83ea6 100644 --- a/auth-krb4.c +++ b/auth-krb4.c @@ -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. */ diff --git a/auth-rhosts.c b/auth-rhosts.c index de5114ed..c1f1034e 100644 --- a/auth-rhosts.c +++ b/auth-rhosts.c @@ -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) diff --git a/canohost.c b/canohost.c index 01ba7112..009b5253 100644 --- a/canohost.c +++ b/canohost.c @@ -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. */ diff --git a/log-server.c b/log-server.c index 8aa20928..1143b348 100644 --- a/log-server.c +++ b/log-server.c @@ -24,6 +24,7 @@ RCSID("$Id$"); 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(); } diff --git a/readconf.c b/readconf.c index e9b251a9..1f43ba0f 100644 --- a/readconf.c +++ b/readconf.c @@ -88,6 +88,7 @@ RCSID("$Id$"); 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 diff --git a/readconf.h b/readconf.h index 06337752..adb39755 100644 --- a/readconf.h +++ b/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); diff --git a/ssh.c b/ssh.c index 72a7984c..702e7d26 100644 --- a/ssh.c +++ b/ssh.c @@ -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: diff --git a/sshconnect.c b/sshconnect.c index 2ca5eaaa..4b5a6660 100644 --- a/sshconnect.c +++ b/sshconnect.c @@ -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); diff --git a/sshd.c b/sshd.c index 362dbe02..e603161e 100644 --- a/sshd.c +++ b/sshd.c @@ -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,313 +1225,263 @@ 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 { + /* 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); +} + +#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; - case SSH_CMSG_HAVE_AFS_TOKEN: - if (!options.afs_token_passing || !k_hasafs()) { + /* 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(pw, 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)) - { - /* 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; } - - 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); + + /* 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); + 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)) - { - /* 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); + 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) { - 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\"", 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. */ - 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; + /* Try authentication with the password. */ + authenticated = auth_password(pw, password); - 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) + memset(password, 0, strlen(password)); + xfree(password); break; - - if (++authentication_failures >= MAX_AUTH_FAILURES) { - packet_disconnect("Too many authentication failures for %.100s from %.200s", - pw->pw_name, get_canonical_hostname()); +#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. */ } - /* Send a message indicating that the authentication attempt failed. */ - packet_start(SSH_SMSG_FAILURE); - packet_send(); - packet_write_wait(); - } - - /* 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."); - 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) @@ -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); - } -#endif /* SKEY */ - 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(); } - /* 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. */ -- 2.45.2