summaryrefslogtreecommitdiffstats
path: root/auth1.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2005-06-19 07:31:37 +1000
committerDamien Miller <djm@mindrot.org>2005-06-19 07:31:37 +1000
commit6abf57ccbf13a043a2a2b7c8a662fc3e50d71d20 (patch)
tree603d697f6d2549cf4818e5338b7da9fd4926eac0 /auth1.c
parentf0bd352429f26f99b7bdacd23baf46b39a9f600a (diff)
- djm@cvs.openbsd.org 2005/05/20 12:57:01;
[auth1.c] split protocol 1 auth methods into separate functions, makes authloop much more readable; fixes and ok markus@ (portable ok & polish dtucker@)
Diffstat (limited to 'auth1.c')
-rw-r--r--auth1.c323
1 files changed, 192 insertions, 131 deletions
diff --git a/auth1.c b/auth1.c
index d0892845..b7dfa987 100644
--- a/auth1.c
+++ b/auth1.c
@@ -10,7 +10,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: auth1.c,v 1.59 2004/07/28 09:40:29 markus Exp $");
+RCSID("$OpenBSD: auth1.c,v 1.60 2005/05/20 12:57:01 djm Exp $");
#include "xmalloc.h"
#include "rsa.h"
@@ -31,28 +31,181 @@ RCSID("$OpenBSD: auth1.c,v 1.59 2004/07/28 09:40:29 markus Exp $");
extern ServerOptions options;
extern Buffer loginmsg;
-/*
- * convert ssh auth msg type into description
- */
+static int auth1_process_password(Authctxt *, char *, size_t);
+static int auth1_process_rsa(Authctxt *, char *, size_t);
+static int auth1_process_rhosts_rsa(Authctxt *, char *, size_t);
+static int auth1_process_tis_challenge(Authctxt *, char *, size_t);
+static int auth1_process_tis_response(Authctxt *, char *, size_t);
+
+static char *client_user = NULL; /* Used to fill in remote user for PAM */
+
+struct AuthMethod1 {
+ int type;
+ char *name;
+ int *enabled;
+ int (*method)(Authctxt *, char *, size_t);
+};
+
+const struct AuthMethod1 auth1_methods[] = {
+ {
+ SSH_CMSG_AUTH_PASSWORD, "password",
+ &options.password_authentication, auth1_process_password
+ },
+ {
+ SSH_CMSG_AUTH_RSA, "rsa",
+ &options.rsa_authentication, auth1_process_rsa
+ },
+ {
+ SSH_CMSG_AUTH_RHOSTS_RSA, "rhosts-rsa",
+ &options.rhosts_rsa_authentication, auth1_process_rhosts_rsa
+ },
+ {
+ SSH_CMSG_AUTH_TIS, "challenge-response",
+ &options.challenge_response_authentication,
+ auth1_process_tis_challenge
+ },
+ {
+ SSH_CMSG_AUTH_TIS_RESPONSE, "challenge-response",
+ &options.challenge_response_authentication,
+ auth1_process_tis_response
+ },
+ { -1, NULL, NULL, NULL}
+};
+
+static const struct AuthMethod1
+*lookup_authmethod1(int type)
+{
+ int i;
+
+ for(i = 0; auth1_methods[i].name != NULL; i++)
+ if (auth1_methods[i].type == type)
+ return (&(auth1_methods[i]));
+
+ return (NULL);
+}
+
static char *
get_authname(int type)
{
- static char buf[1024];
- switch (type) {
- case SSH_CMSG_AUTH_PASSWORD:
- return "password";
- case SSH_CMSG_AUTH_RSA:
- return "rsa";
- case SSH_CMSG_AUTH_RHOSTS_RSA:
- return "rhosts-rsa";
- case SSH_CMSG_AUTH_RHOSTS:
- return "rhosts";
- case SSH_CMSG_AUTH_TIS:
- case SSH_CMSG_AUTH_TIS_RESPONSE:
- return "challenge-response";
+ const struct AuthMethod1 *a;
+ static char buf[64];
+
+ if ((a = lookup_authmethod1(type)) != NULL)
+ return (a->name);
+ snprintf(buf, sizeof(buf), "bad-auth-msg-%d", type);
+ return (buf);
+}
+
+static int
+auth1_process_password(Authctxt *authctxt, char *info, size_t infolen)
+{
+ int authenticated = 0;
+ char *password;
+ u_int dlen;
+
+ /*
+ * 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_check_eom();
+
+ /* Try authentication with the password. */
+ authenticated = PRIVSEP(auth_password(authctxt, password));
+
+ memset(password, 0, dlen);
+ xfree(password);
+
+ return (authenticated);
+}
+
+static int
+auth1_process_rsa(Authctxt *authctxt, char *info, size_t infolen)
+{
+ int authenticated = 0;
+ BIGNUM *n;
+
+ /* RSA authentication requested. */
+ if ((n = BN_new()) == NULL)
+ fatal("do_authloop: BN_new failed");
+ packet_get_bignum(n);
+ packet_check_eom();
+ authenticated = auth_rsa(authctxt, n);
+ BN_clear_free(n);
+
+ return (authenticated);
+}
+
+static int
+auth1_process_rhosts_rsa(Authctxt *authctxt, char *info, size_t infolen)
+{
+ int authenticated = 0;
+ u_int bits;
+ Key *client_host_key;
+ u_int ulen;
+
+ /*
+ * 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 = key_new(KEY_RSA1);
+ bits = packet_get_int();
+ packet_get_bignum(client_host_key->rsa->e);
+ packet_get_bignum(client_host_key->rsa->n);
+
+ if (bits != BN_num_bits(client_host_key->rsa->n)) {
+ verbose("Warning: keysize mismatch for client_host_key: "
+ "actual %d, announced %d",
+ BN_num_bits(client_host_key->rsa->n), bits);
}
- snprintf(buf, sizeof buf, "bad-auth-msg-%d", type);
- return buf;
+ packet_check_eom();
+
+ authenticated = auth_rhosts_rsa(authctxt, client_user,
+ client_host_key);
+ key_free(client_host_key);
+
+ snprintf(info, infolen, " ruser %.100s", client_user);
+
+ return (authenticated);
+}
+
+static int
+auth1_process_tis_challenge(Authctxt *authctxt, char *info, size_t infolen)
+{
+ char *challenge;
+
+ if ((challenge = get_challenge(authctxt)) == NULL)
+ return (0);
+
+ debug("sending challenge '%s'", challenge);
+ packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
+ packet_put_cstring(challenge);
+ xfree(challenge);
+ packet_send();
+ packet_write_wait();
+
+ return (-1);
+}
+
+static int
+auth1_process_tis_response(Authctxt *authctxt, char *info, size_t infolen)
+{
+ int authenticated = 0;
+ char *response;
+ u_int dlen;
+
+ response = packet_get_string(&dlen);
+ packet_check_eom();
+ authenticated = verify_response(authctxt, response);
+ memset(response, 'r', dlen);
+ xfree(response);
+
+ return (authenticated);
}
/*
@@ -63,14 +216,9 @@ static void
do_authloop(Authctxt *authctxt)
{
int authenticated = 0;
- u_int bits;
- Key *client_host_key;
- BIGNUM *n;
- char *client_user, *password;
char info[1024];
- u_int dlen;
- u_int ulen;
- int prev, type = 0;
+ int prev = 0, type = 0;
+ const struct AuthMethod1 *meth;
debug("Attempting authentication for %s%.100s.",
authctxt->valid ? "" : "invalid user ", authctxt->user);
@@ -95,8 +243,6 @@ do_authloop(Authctxt *authctxt)
packet_send();
packet_write_wait();
- client_user = NULL;
-
for (;;) {
/* default to fail */
authenticated = 0;
@@ -118,107 +264,21 @@ do_authloop(Authctxt *authctxt)
type != SSH_CMSG_AUTH_TIS_RESPONSE)
abandon_challenge_response(authctxt);
- /* Process the packet. */
- switch (type) {
- case SSH_CMSG_AUTH_RHOSTS_RSA:
- if (!options.rhosts_rsa_authentication) {
- verbose("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 = key_new(KEY_RSA1);
- bits = packet_get_int();
- packet_get_bignum(client_host_key->rsa->e);
- packet_get_bignum(client_host_key->rsa->n);
-
- if (bits != BN_num_bits(client_host_key->rsa->n))
- verbose("Warning: keysize mismatch for client_host_key: "
- "actual %d, announced %d",
- BN_num_bits(client_host_key->rsa->n), bits);
- packet_check_eom();
-
- authenticated = auth_rhosts_rsa(authctxt, client_user,
- client_host_key);
- key_free(client_host_key);
-
- snprintf(info, sizeof info, " ruser %.100s", client_user);
- break;
-
- case SSH_CMSG_AUTH_RSA:
- if (!options.rsa_authentication) {
- verbose("RSA authentication disabled.");
- break;
- }
- /* RSA authentication requested. */
- if ((n = BN_new()) == NULL)
- fatal("do_authloop: BN_new failed");
- packet_get_bignum(n);
- packet_check_eom();
- authenticated = auth_rsa(authctxt, n);
- BN_clear_free(n);
- break;
-
- case SSH_CMSG_AUTH_PASSWORD:
- if (!options.password_authentication) {
- verbose("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_check_eom();
-
- /* Try authentication with the password. */
- authenticated = PRIVSEP(auth_password(authctxt, password));
-
- memset(password, 0, strlen(password));
- xfree(password);
- break;
-
- case SSH_CMSG_AUTH_TIS:
- debug("rcvd SSH_CMSG_AUTH_TIS");
- if (options.challenge_response_authentication == 1) {
- char *challenge = get_challenge(authctxt);
- if (challenge != NULL) {
- debug("sending challenge '%s'", challenge);
- packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
- packet_put_cstring(challenge);
- xfree(challenge);
- packet_send();
- packet_write_wait();
- continue;
- }
- }
- break;
- case SSH_CMSG_AUTH_TIS_RESPONSE:
- debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
- if (options.challenge_response_authentication == 1) {
- char *response = packet_get_string(&dlen);
- packet_check_eom();
- authenticated = verify_response(authctxt, response);
- memset(response, 'r', dlen);
- xfree(response);
- }
- break;
-
- default:
- /*
- * Any unknown messages will be ignored (and failure
- * returned) during authentication.
- */
- logit("Unknown message during authentication: type %d", type);
- break;
+ if ((meth = lookup_authmethod1(type)) == NULL) {
+ logit("Unknown message during authentication: "
+ "type %d", type);
+ goto skip;
+ }
+
+ if (!*(meth->enabled)) {
+ verbose("%s authentication disabled.", meth->name);
+ goto skip;
}
+
+ authenticated = meth->method(authctxt, info, sizeof(info));
+ if (authenticated == -1)
+ continue; /* "postponed" */
+
#ifdef BSD_AUTH
if (authctxt->as) {
auth_close(authctxt->as);
@@ -247,8 +307,8 @@ do_authloop(Authctxt *authctxt)
#else
/* Special handling for root */
if (authenticated && authctxt->pw->pw_uid == 0 &&
- !auth_root_allowed(get_authname(type))) {
- authenticated = 0;
+ !auth_root_allowed(meth->name)) {
+ authenticated = 0;
# ifdef SSH_AUDIT_EVENTS
PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED));
# endif
@@ -276,6 +336,7 @@ do_authloop(Authctxt *authctxt)
}
#endif
+ skip:
/* Log before sending the reply */
auth_log(authctxt, authenticated, get_authname(type), info);
@@ -341,7 +402,7 @@ do_authentication(Authctxt *authctxt)
/*
* If we are not running as root, the user must have the same uid as
- * the server. (Unless you are running Windows)
+ * the server.
*/
#ifndef HAVE_CYGWIN
if (!use_privsep && getuid() != 0 && authctxt->pw &&