version 1.59, 2004/07/28 09:40:29 |
version 1.59.4.1, 2005/09/04 18:39:56 |
|
|
/* import */ |
/* import */ |
extern ServerOptions options; |
extern ServerOptions options; |
|
|
/* |
static int auth1_process_password(Authctxt *, char *, size_t); |
* convert ssh auth msg type into description |
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); |
|
|
|
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 * |
static char * |
get_authname(int type) |
get_authname(int type) |
{ |
{ |
static char buf[1024]; |
const struct AuthMethod1 *a; |
switch (type) { |
static char buf[64]; |
case SSH_CMSG_AUTH_PASSWORD: |
|
return "password"; |
if ((a = lookup_authmethod1(type)) != NULL) |
case SSH_CMSG_AUTH_RSA: |
return (a->name); |
return "rsa"; |
snprintf(buf, sizeof(buf), "bad-auth-msg-%d", type); |
case SSH_CMSG_AUTH_RHOSTS_RSA: |
return (buf); |
return "rhosts-rsa"; |
} |
case SSH_CMSG_AUTH_RHOSTS: |
|
return "rhosts"; |
static int |
case SSH_CMSG_AUTH_TIS: |
auth1_process_password(Authctxt *authctxt, char *info, size_t infolen) |
case SSH_CMSG_AUTH_TIS_RESPONSE: |
{ |
return "challenge-response"; |
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 keybits, authenticated = 0; |
|
u_int bits; |
|
char *client_user; |
|
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); |
|
|
|
keybits = BN_num_bits(client_host_key->rsa->n); |
|
if (keybits < 0 || bits != (u_int)keybits) { |
|
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); |
packet_check_eom(); |
return buf; |
|
|
authenticated = auth_rhosts_rsa(authctxt, client_user, |
|
client_host_key); |
|
key_free(client_host_key); |
|
|
|
snprintf(info, infolen, " ruser %.100s", client_user); |
|
xfree(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); |
|
} |
|
|
/* |
/* |
* read packets, try to authenticate the user and |
* read packets, try to authenticate the user and |
* return only if authentication is successful |
* return only if authentication is successful |
|
|
do_authloop(Authctxt *authctxt) |
do_authloop(Authctxt *authctxt) |
{ |
{ |
int authenticated = 0; |
int authenticated = 0; |
u_int bits; |
|
Key *client_host_key; |
|
BIGNUM *n; |
|
char *client_user, *password; |
|
char info[1024]; |
char info[1024]; |
u_int dlen; |
|
u_int ulen; |
|
int type = 0; |
int type = 0; |
|
const struct AuthMethod1 *meth; |
|
|
debug("Attempting authentication for %s%.100s.", |
debug("Attempting authentication for %s%.100s.", |
authctxt->valid ? "" : "invalid user ", authctxt->user); |
authctxt->valid ? "" : "invalid user ", authctxt->user); |
|
|
|
|
/* Get a packet from the client. */ |
/* Get a packet from the client. */ |
type = packet_read(); |
type = packet_read(); |
|
if ((meth = lookup_authmethod1(type)) == NULL) { |
|
logit("Unknown message during authentication: " |
|
"type %d", type); |
|
goto skip; |
|
} |
|
|
/* Process the packet. */ |
if (!*(meth->enabled)) { |
switch (type) { |
verbose("%s authentication disabled.", meth->name); |
case SSH_CMSG_AUTH_RHOSTS_RSA: |
goto skip; |
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. */ |
authenticated = meth->method(authctxt, info, sizeof(info)); |
client_host_key = key_new(KEY_RSA1); |
if (authenticated == -1) |
bits = packet_get_int(); |
continue; /* "postponed" */ |
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); |
|
xfree(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; |
|
} |
|
#ifdef BSD_AUTH |
#ifdef BSD_AUTH |
if (authctxt->as) { |
if (authctxt->as) { |
auth_close(authctxt->as); |
auth_close(authctxt->as); |
|
|
|
|
/* Special handling for root */ |
/* Special handling for root */ |
if (authenticated && authctxt->pw->pw_uid == 0 && |
if (authenticated && authctxt->pw->pw_uid == 0 && |
!auth_root_allowed(get_authname(type))) |
!auth_root_allowed(meth->name)) |
authenticated = 0; |
authenticated = 0; |
|
|
|
skip: |
/* Log before sending the reply */ |
/* Log before sending the reply */ |
auth_log(authctxt, authenticated, get_authname(type), info); |
auth_log(authctxt, authenticated, get_authname(type), info); |
|
|