version 1.120, 2003/06/24 08:23:46 |
version 1.121, 2003/08/22 10:56:09 |
|
|
#include "msg.h" |
#include "msg.h" |
#include "pathnames.h" |
#include "pathnames.h" |
|
|
|
#ifdef GSSAPI |
|
#include "ssh-gss.h" |
|
#endif |
|
|
/* import */ |
/* import */ |
extern char *client_version_string; |
extern char *client_version_string; |
extern char *server_version_string; |
extern char *server_version_string; |
|
|
Sensitive *sensitive; |
Sensitive *sensitive; |
/* kbd-interactive */ |
/* kbd-interactive */ |
int info_req_seen; |
int info_req_seen; |
|
/* generic */ |
|
void *methoddata; |
}; |
}; |
struct Authmethod { |
struct Authmethod { |
char *name; /* string to compare against server's list */ |
char *name; /* string to compare against server's list */ |
|
|
int userauth_hostbased(Authctxt *); |
int userauth_hostbased(Authctxt *); |
int userauth_kerberos(Authctxt *); |
int userauth_kerberos(Authctxt *); |
|
|
|
#ifdef GSSAPI |
|
int userauth_gssapi(Authctxt *authctxt); |
|
void input_gssapi_response(int type, u_int32_t, void *); |
|
void input_gssapi_token(int type, u_int32_t, void *); |
|
void input_gssapi_hash(int type, u_int32_t, void *); |
|
void input_gssapi_error(int, u_int32_t, void *); |
|
void input_gssapi_errtok(int, u_int32_t, void *); |
|
#endif |
|
|
void userauth(Authctxt *, char *); |
void userauth(Authctxt *, char *); |
|
|
static int sign_and_send_pubkey(Authctxt *, Identity *); |
static int sign_and_send_pubkey(Authctxt *, Identity *); |
|
|
static char *authmethods_get(void); |
static char *authmethods_get(void); |
|
|
Authmethod authmethods[] = { |
Authmethod authmethods[] = { |
|
#ifdef GSSAPI |
|
{"gssapi", |
|
userauth_gssapi, |
|
&options.gss_authentication, |
|
NULL}, |
|
#endif |
{"hostbased", |
{"hostbased", |
userauth_hostbased, |
userauth_hostbased, |
&options.hostbased_authentication, |
&options.hostbased_authentication, |
|
|
authctxt.success = 0; |
authctxt.success = 0; |
authctxt.method = authmethod_lookup("none"); |
authctxt.method = authmethod_lookup("none"); |
authctxt.authlist = NULL; |
authctxt.authlist = NULL; |
|
authctxt.methoddata = NULL; |
authctxt.sensitive = sensitive; |
authctxt.sensitive = sensitive; |
authctxt.info_req_seen = 0; |
authctxt.info_req_seen = 0; |
if (authctxt.method == NULL) |
if (authctxt.method == NULL) |
|
|
void |
void |
userauth(Authctxt *authctxt, char *authlist) |
userauth(Authctxt *authctxt, char *authlist) |
{ |
{ |
|
if (authctxt->methoddata) { |
|
xfree(authctxt->methoddata); |
|
authctxt->methoddata = NULL; |
|
} |
if (authlist == NULL) { |
if (authlist == NULL) { |
authlist = authctxt->authlist; |
authlist = authctxt->authlist; |
} else { |
} else { |
|
|
fatal("input_userauth_success: no authentication context"); |
fatal("input_userauth_success: no authentication context"); |
if (authctxt->authlist) |
if (authctxt->authlist) |
xfree(authctxt->authlist); |
xfree(authctxt->authlist); |
|
if (authctxt->methoddata) |
|
xfree(authctxt->methoddata); |
authctxt->success = 1; /* break out */ |
authctxt->success = 1; /* break out */ |
} |
} |
|
|
|
|
if (sent == 0) |
if (sent == 0) |
userauth(authctxt, NULL); |
userauth(authctxt, NULL); |
} |
} |
|
|
|
#ifdef GSSAPI |
|
int |
|
userauth_gssapi(Authctxt *authctxt) |
|
{ |
|
Gssctxt *gssctxt = NULL; |
|
static gss_OID_set supported = NULL; |
|
static int mech = 0; |
|
OM_uint32 min; |
|
int ok = 0; |
|
|
|
/* Try one GSSAPI method at a time, rather than sending them all at |
|
* once. */ |
|
|
|
if (supported == NULL) |
|
gss_indicate_mechs(&min, &supported); |
|
|
|
/* Check to see if the mechanism is usable before we offer it */ |
|
while (mech<supported->count && !ok) { |
|
if (gssctxt) |
|
ssh_gssapi_delete_ctx(&gssctxt); |
|
ssh_gssapi_build_ctx(&gssctxt); |
|
ssh_gssapi_set_oid(gssctxt, &supported->elements[mech]); |
|
|
|
/* My DER encoding requires length<128 */ |
|
if (supported->elements[mech].length < 128 && |
|
!GSS_ERROR(ssh_gssapi_import_name(gssctxt, |
|
authctxt->host))) { |
|
ok = 1; /* Mechanism works */ |
|
} else { |
|
mech++; |
|
} |
|
} |
|
|
|
if (!ok) return 0; |
|
|
|
authctxt->methoddata=(void *)gssctxt; |
|
|
|
packet_start(SSH2_MSG_USERAUTH_REQUEST); |
|
packet_put_cstring(authctxt->server_user); |
|
packet_put_cstring(authctxt->service); |
|
packet_put_cstring(authctxt->method->name); |
|
|
|
packet_put_int(1); |
|
|
|
/* Some servers encode the OID incorrectly (as we used to) */ |
|
if (datafellows & SSH_BUG_GSSAPI_BER) { |
|
packet_put_string(supported->elements[mech].elements, |
|
supported->elements[mech].length); |
|
} else { |
|
packet_put_int((supported->elements[mech].length)+2); |
|
packet_put_char(SSH_GSS_OIDTYPE); |
|
packet_put_char(supported->elements[mech].length); |
|
packet_put_raw(supported->elements[mech].elements, |
|
supported->elements[mech].length); |
|
} |
|
|
|
packet_send(); |
|
|
|
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE, &input_gssapi_response); |
|
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token); |
|
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR, &input_gssapi_error); |
|
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok); |
|
|
|
mech++; /* Move along to next candidate */ |
|
|
|
return 1; |
|
} |
|
|
|
void |
|
input_gssapi_response(int type, u_int32_t plen, void *ctxt) |
|
{ |
|
Authctxt *authctxt = ctxt; |
|
Gssctxt *gssctxt; |
|
OM_uint32 status, ms; |
|
int oidlen; |
|
char *oidv; |
|
gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; |
|
|
|
if (authctxt == NULL) |
|
fatal("input_gssapi_response: no authentication context"); |
|
gssctxt = authctxt->methoddata; |
|
|
|
/* Setup our OID */ |
|
oidv = packet_get_string(&oidlen); |
|
|
|
if (datafellows & SSH_BUG_GSSAPI_BER) { |
|
if (!ssh_gssapi_check_oid(gssctxt, oidv, oidlen)) |
|
fatal("Server returned different OID than expected"); |
|
} else { |
|
if(oidv[0] != SSH_GSS_OIDTYPE || oidv[1] != oidlen-2) { |
|
debug("Badly encoded mechanism OID received"); |
|
userauth(authctxt, NULL); |
|
xfree(oidv); |
|
return; |
|
} |
|
if (!ssh_gssapi_check_oid(gssctxt, oidv+2, oidlen-2)) |
|
fatal("Server returned different OID than expected"); |
|
} |
|
|
|
packet_check_eom(); |
|
|
|
xfree(oidv); |
|
|
|
status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, |
|
GSS_C_NO_BUFFER, &send_tok, NULL); |
|
if (GSS_ERROR(status)) { |
|
if (send_tok.length > 0) { |
|
packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); |
|
packet_put_string(send_tok.value, send_tok.length); |
|
packet_send(); |
|
gss_release_buffer(&ms, &send_tok); |
|
} |
|
/* Start again with next method on list */ |
|
debug("Trying to start again"); |
|
userauth(authctxt, NULL); |
|
return; |
|
} |
|
|
|
/* We must have data to send */ |
|
packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); |
|
packet_put_string(send_tok.value, send_tok.length); |
|
packet_send(); |
|
gss_release_buffer(&ms, &send_tok); |
|
} |
|
|
|
void |
|
input_gssapi_token(int type, u_int32_t plen, void *ctxt) |
|
{ |
|
Authctxt *authctxt = ctxt; |
|
Gssctxt *gssctxt; |
|
gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; |
|
gss_buffer_desc recv_tok; |
|
OM_uint32 status, ms; |
|
u_int slen; |
|
|
|
if (authctxt == NULL) |
|
fatal("input_gssapi_response: no authentication context"); |
|
gssctxt = authctxt->methoddata; |
|
|
|
recv_tok.value = packet_get_string(&slen); |
|
recv_tok.length = slen; /* safe typecast */ |
|
|
|
packet_check_eom(); |
|
|
|
status=ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, |
|
&recv_tok, &send_tok, NULL); |
|
|
|
xfree(recv_tok.value); |
|
|
|
if (GSS_ERROR(status)) { |
|
if (send_tok.length > 0) { |
|
packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); |
|
packet_put_string(send_tok.value, send_tok.length); |
|
packet_send(); |
|
gss_release_buffer(&ms, &send_tok); |
|
} |
|
/* Start again with the next method in the list */ |
|
userauth(authctxt, NULL); |
|
return; |
|
} |
|
|
|
if (send_tok.length > 0) { |
|
packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); |
|
packet_put_string(send_tok.value, send_tok.length); |
|
packet_send(); |
|
gss_release_buffer(&ms, &send_tok); |
|
} |
|
|
|
if (status == GSS_S_COMPLETE) { |
|
/* If that succeeded, send a exchange complete message */ |
|
packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE); |
|
packet_send(); |
|
} |
|
} |
|
|
|
void |
|
input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) |
|
{ |
|
Authctxt *authctxt = ctxt; |
|
Gssctxt *gssctxt; |
|
gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; |
|
gss_buffer_desc recv_tok; |
|
OM_uint32 status, ms; |
|
|
|
if (authctxt == NULL) |
|
fatal("input_gssapi_response: no authentication context"); |
|
gssctxt = authctxt->methoddata; |
|
|
|
recv_tok.value = packet_get_string(&recv_tok.length); |
|
|
|
packet_check_eom(); |
|
|
|
/* Stick it into GSSAPI and see what it says */ |
|
status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, |
|
&recv_tok, &send_tok, NULL); |
|
|
|
xfree(recv_tok.value); |
|
gss_release_buffer(&ms, &send_tok); |
|
|
|
/* Server will be returning a failed packet after this one */ |
|
} |
|
|
|
void |
|
input_gssapi_error(int type, u_int32_t plen, void *ctxt) |
|
{ |
|
OM_uint32 maj, min; |
|
char *msg; |
|
char *lang; |
|
|
|
maj=packet_get_int(); |
|
min=packet_get_int(); |
|
msg=packet_get_string(NULL); |
|
lang=packet_get_string(NULL); |
|
|
|
packet_check_eom(); |
|
|
|
debug("Server GSSAPI Error:\n%s\n", msg); |
|
xfree(msg); |
|
xfree(lang); |
|
} |
|
#endif /* GSSAPI */ |
|
|
int |
int |
userauth_none(Authctxt *authctxt) |
userauth_none(Authctxt *authctxt) |