version 1.277, 2018/07/09 13:37:10 |
version 1.278, 2018/07/09 21:03:30 |
|
|
#include "xmalloc.h" |
#include "xmalloc.h" |
#include "ssh.h" |
#include "ssh.h" |
#include "ssh2.h" |
#include "ssh2.h" |
#include "buffer.h" |
#include "sshbuf.h" |
#include "packet.h" |
#include "packet.h" |
#include "compat.h" |
#include "compat.h" |
#include "cipher.h" |
#include "cipher.h" |
#include "key.h" |
#include "sshkey.h" |
#include "kex.h" |
#include "kex.h" |
#include "myproposal.h" |
#include "myproposal.h" |
#include "sshconnect.h" |
#include "sshconnect.h" |
|
|
|
|
#ifdef DEBUG_KEXDH |
#ifdef DEBUG_KEXDH |
/* send 1st encrypted/maced/compressed message */ |
/* send 1st encrypted/maced/compressed message */ |
packet_start(SSH2_MSG_IGNORE); |
if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 || |
packet_put_cstring("markus"); |
(r = sshpkt_put_cstring(ssh, "markus")) != 0 || |
packet_send(); |
(r = sshpkt_send(ssh)) != 0) |
packet_write_wait(); |
fatal("%s: %s", __func__, ssh_err(r)); |
|
ssh_packet_write_wait(ssh); |
#endif |
#endif |
} |
} |
|
|
|
|
void |
void |
userauth(Authctxt *authctxt, char *authlist) |
userauth(Authctxt *authctxt, char *authlist) |
{ |
{ |
|
struct ssh *ssh = active_state; /* XXX */ |
|
|
if (authctxt->method != NULL && authctxt->method->cleanup != NULL) |
if (authctxt->method != NULL && authctxt->method->cleanup != NULL) |
authctxt->method->cleanup(authctxt); |
authctxt->method->cleanup(authctxt); |
|
|
|
|
authctxt->method = method; |
authctxt->method = method; |
|
|
/* reset the per method handler */ |
/* reset the per method handler */ |
dispatch_range(SSH2_MSG_USERAUTH_PER_METHOD_MIN, |
ssh_dispatch_range(ssh, SSH2_MSG_USERAUTH_PER_METHOD_MIN, |
SSH2_MSG_USERAUTH_PER_METHOD_MAX, NULL); |
SSH2_MSG_USERAUTH_PER_METHOD_MAX, NULL); |
|
|
/* and try new method */ |
/* and try new method */ |
|
|
{ |
{ |
Authctxt *authctxt = ssh->authctxt; |
Authctxt *authctxt = ssh->authctxt; |
char *authlist = NULL; |
char *authlist = NULL; |
int partial; |
u_char partial; |
|
int r; |
|
|
if (authctxt == NULL) |
if (authctxt == NULL) |
fatal("input_userauth_failure: no authentication context"); |
fatal("input_userauth_failure: no authentication context"); |
|
|
authlist = packet_get_string(NULL); |
if ((r = sshpkt_get_cstring(ssh, &authlist, NULL)) != 0 || |
partial = packet_get_char(); |
(r = sshpkt_get_u8(ssh, &partial)) != 0 || |
packet_check_eom(); |
(r = sshpkt_get_end(ssh)) != 0) |
|
goto out; |
|
|
if (partial != 0) { |
if (partial != 0) { |
verbose("Authenticated with partial success."); |
verbose("Authenticated with partial success."); |
|
|
debug("Authentications that can continue: %s", authlist); |
debug("Authentications that can continue: %s", authlist); |
|
|
userauth(authctxt, authlist); |
userauth(authctxt, authlist); |
|
authlist = NULL; |
|
out: |
|
free(authlist); |
return 0; |
return 0; |
} |
} |
|
|
|
|
struct sshkey *key = NULL; |
struct sshkey *key = NULL; |
Identity *id = NULL; |
Identity *id = NULL; |
int pktype, sent = 0; |
int pktype, sent = 0; |
u_int alen, blen; |
size_t blen; |
char *pkalg, *fp; |
char *pkalg = NULL, *fp; |
u_char *pkblob; |
u_char *pkblob = NULL; |
|
int r; |
|
|
if (authctxt == NULL) |
if (authctxt == NULL) |
fatal("input_userauth_pk_ok: no authentication context"); |
fatal("input_userauth_pk_ok: no authentication context"); |
|
|
pkalg = packet_get_string(&alen); |
if ((r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 || |
pkblob = packet_get_string(&blen); |
(r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 || |
packet_check_eom(); |
(r = sshpkt_get_end(ssh)) != 0) |
|
goto done; |
|
|
debug("Server accepts key: pkalg %s blen %u", pkalg, blen); |
debug("Server accepts key: pkalg %s blen %zu", pkalg, blen); |
|
|
if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) { |
if ((pktype = sshkey_type_from_name(pkalg)) == KEY_UNSPEC) { |
debug("unknown pkalg %s", pkalg); |
debug("unknown pkalg %s", pkalg); |
goto done; |
goto done; |
} |
} |
if ((key = key_from_blob(pkblob, blen)) == NULL) { |
if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) { |
debug("no key from blob. pkalg %s", pkalg); |
debug("no key from blob. pkalg %s: %s", pkalg, ssh_err(r)); |
goto done; |
goto done; |
} |
} |
if (key->type != pktype) { |
if (key->type != pktype) { |
|
|
* duplicate keys |
* duplicate keys |
*/ |
*/ |
TAILQ_FOREACH_REVERSE(id, &authctxt->keys, idlist, next) { |
TAILQ_FOREACH_REVERSE(id, &authctxt->keys, idlist, next) { |
if (key_equal(key, id->key)) { |
if (sshkey_equal(key, id->key)) { |
sent = sign_and_send_pubkey(ssh, authctxt, id); |
sent = sign_and_send_pubkey(ssh, authctxt, id); |
break; |
break; |
} |
} |
} |
} |
done: |
r = 0; |
key_free(key); |
done: |
|
sshkey_free(key); |
free(pkalg); |
free(pkalg); |
free(pkblob); |
free(pkblob); |
|
|
/* try another method if we did not send a packet */ |
/* try another method if we did not send a packet */ |
if (sent == 0) |
if (r == 0 && sent == 0) |
userauth(authctxt, NULL); |
userauth(authctxt, NULL); |
return 0; |
return r; |
} |
} |
|
|
#ifdef GSSAPI |
#ifdef GSSAPI |
int |
int |
userauth_gssapi(Authctxt *authctxt) |
userauth_gssapi(Authctxt *authctxt) |
{ |
{ |
|
struct ssh *ssh = active_state; /* XXX */ |
Gssctxt *gssctxt = NULL; |
Gssctxt *gssctxt = NULL; |
static gss_OID_set gss_supported = NULL; |
static gss_OID_set gss_supported = NULL; |
static u_int mech = 0; |
static u_int mech = 0; |
OM_uint32 min; |
OM_uint32 min; |
int ok = 0; |
int r, ok = 0; |
|
|
/* Try one GSSAPI method at a time, rather than sending them all at |
/* Try one GSSAPI method at a time, rather than sending them all at |
* once. */ |
* once. */ |
|
|
|
|
authctxt->methoddata=(void *)gssctxt; |
authctxt->methoddata=(void *)gssctxt; |
|
|
packet_start(SSH2_MSG_USERAUTH_REQUEST); |
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || |
packet_put_cstring(authctxt->server_user); |
(r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || |
packet_put_cstring(authctxt->service); |
(r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || |
packet_put_cstring(authctxt->method->name); |
(r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || |
|
(r = sshpkt_put_u32(ssh, 1)) != 0 || |
|
(r = sshpkt_put_u32(ssh, |
|
(gss_supported->elements[mech].length) + 2)) != 0 || |
|
(r = sshpkt_put_u8(ssh, SSH_GSS_OIDTYPE)) != 0 || |
|
(r = sshpkt_put_u8(ssh, |
|
gss_supported->elements[mech].length)) != 0 || |
|
(r = sshpkt_put(ssh, |
|
gss_supported->elements[mech].elements, |
|
gss_supported->elements[mech].length)) != 0 || |
|
(r = sshpkt_send(ssh)) != 0) |
|
fatal("%s: %s", __func__, ssh_err(r)); |
|
|
packet_put_int(1); |
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_RESPONSE, &input_gssapi_response); |
|
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token); |
|
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERROR, &input_gssapi_error); |
|
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok); |
|
|
packet_put_int((gss_supported->elements[mech].length) + 2); |
|
packet_put_char(SSH_GSS_OIDTYPE); |
|
packet_put_char(gss_supported->elements[mech].length); |
|
packet_put_raw(gss_supported->elements[mech].elements, |
|
gss_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 */ |
mech++; /* Move along to next candidate */ |
|
|
return 1; |
return 1; |
|
|
gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; |
gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; |
gss_buffer_desc gssbuf; |
gss_buffer_desc gssbuf; |
OM_uint32 status, ms, flags; |
OM_uint32 status, ms, flags; |
Buffer b; |
int r; |
|
|
status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, |
status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, |
recv_tok, &send_tok, &flags); |
recv_tok, &send_tok, &flags); |
|
|
if (send_tok.length > 0) { |
if (send_tok.length > 0) { |
if (GSS_ERROR(status)) |
u_char type = GSS_ERROR(status) ? |
packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); |
SSH2_MSG_USERAUTH_GSSAPI_ERRTOK : |
else |
SSH2_MSG_USERAUTH_GSSAPI_TOKEN; |
packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); |
|
|
|
packet_put_string(send_tok.value, send_tok.length); |
if ((r = sshpkt_start(ssh, type)) != 0 || |
packet_send(); |
(r = sshpkt_put_string(ssh, send_tok.value, |
|
send_tok.length)) != 0 || |
|
(r = sshpkt_send(ssh)) != 0) |
|
fatal("%s: %s", __func__, ssh_err(r)); |
|
|
gss_release_buffer(&ms, &send_tok); |
gss_release_buffer(&ms, &send_tok); |
} |
} |
|
|
if (status == GSS_S_COMPLETE) { |
if (status == GSS_S_COMPLETE) { |
/* send either complete or MIC, depending on mechanism */ |
/* send either complete or MIC, depending on mechanism */ |
if (!(flags & GSS_C_INTEG_FLAG)) { |
if (!(flags & GSS_C_INTEG_FLAG)) { |
packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE); |
if ((r = sshpkt_start(ssh, |
packet_send(); |
SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE)) != 0 || |
|
(r = sshpkt_send(ssh)) != 0) |
|
fatal("%s: %s", __func__, ssh_err(r)); |
} else { |
} else { |
ssh_gssapi_buildmic(&b, authctxt->server_user, |
struct sshbuf *b; |
|
|
|
if ((b = sshbuf_new()) == NULL) |
|
fatal("%s: sshbuf_new failed", __func__); |
|
ssh_gssapi_buildmic(b, authctxt->server_user, |
authctxt->service, "gssapi-with-mic"); |
authctxt->service, "gssapi-with-mic"); |
|
|
gssbuf.value = buffer_ptr(&b); |
if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL) |
gssbuf.length = buffer_len(&b); |
fatal("%s: sshbuf_mutable_ptr failed", __func__); |
|
gssbuf.length = sshbuf_len(b); |
|
|
status = ssh_gssapi_sign(gssctxt, &gssbuf, &mic); |
status = ssh_gssapi_sign(gssctxt, &gssbuf, &mic); |
|
|
if (!GSS_ERROR(status)) { |
if (!GSS_ERROR(status)) { |
packet_start(SSH2_MSG_USERAUTH_GSSAPI_MIC); |
if ((r = sshpkt_start(ssh, |
packet_put_string(mic.value, mic.length); |
SSH2_MSG_USERAUTH_GSSAPI_MIC)) != 0 || |
|
(r = sshpkt_put_string(ssh, mic.value, |
packet_send(); |
mic.length)) != 0 || |
|
(r = sshpkt_send(ssh)) != 0) |
|
fatal("%s: %s", __func__, ssh_err(r)); |
} |
} |
|
|
buffer_free(&b); |
sshbuf_free(b); |
gss_release_buffer(&ms, &mic); |
gss_release_buffer(&ms, &mic); |
} |
} |
} |
} |
|
|
{ |
{ |
Authctxt *authctxt = ssh->authctxt; |
Authctxt *authctxt = ssh->authctxt; |
Gssctxt *gssctxt; |
Gssctxt *gssctxt; |
int oidlen; |
size_t oidlen; |
char *oidv; |
u_char *oidv = NULL; |
|
int r; |
|
|
if (authctxt == NULL) |
if (authctxt == NULL) |
fatal("input_gssapi_response: no authentication context"); |
fatal("input_gssapi_response: no authentication context"); |
gssctxt = authctxt->methoddata; |
gssctxt = authctxt->methoddata; |
|
|
/* Setup our OID */ |
/* Setup our OID */ |
oidv = packet_get_string(&oidlen); |
if ((r = sshpkt_get_string(ssh, &oidv, &oidlen)) != 0) |
|
goto done; |
|
|
if (oidlen <= 2 || |
if (oidlen <= 2 || |
oidv[0] != SSH_GSS_OIDTYPE || |
oidv[0] != SSH_GSS_OIDTYPE || |
oidv[1] != oidlen - 2) { |
oidv[1] != oidlen - 2) { |
free(oidv); |
|
debug("Badly encoded mechanism OID received"); |
debug("Badly encoded mechanism OID received"); |
userauth(authctxt, NULL); |
userauth(authctxt, NULL); |
return 0; |
goto ok; |
} |
} |
|
|
if (!ssh_gssapi_check_oid(gssctxt, oidv + 2, oidlen - 2)) |
if (!ssh_gssapi_check_oid(gssctxt, oidv + 2, oidlen - 2)) |
fatal("Server returned different OID than expected"); |
fatal("Server returned different OID than expected"); |
|
|
packet_check_eom(); |
if ((r = sshpkt_get_end(ssh)) != 0) |
|
goto done; |
|
|
free(oidv); |
|
|
|
if (GSS_ERROR(process_gssapi_token(ssh, GSS_C_NO_BUFFER))) { |
if (GSS_ERROR(process_gssapi_token(ssh, GSS_C_NO_BUFFER))) { |
/* Start again with next method on list */ |
/* Start again with next method on list */ |
debug("Trying to start again"); |
debug("Trying to start again"); |
userauth(authctxt, NULL); |
userauth(authctxt, NULL); |
return 0; |
goto ok; |
} |
} |
return 0; |
ok: |
|
r = 0; |
|
done: |
|
free(oidv); |
|
return r; |
} |
} |
|
|
/* ARGSUSED */ |
/* ARGSUSED */ |
|
|
{ |
{ |
Authctxt *authctxt = ssh->authctxt; |
Authctxt *authctxt = ssh->authctxt; |
gss_buffer_desc recv_tok; |
gss_buffer_desc recv_tok; |
|
u_char *p = NULL; |
|
size_t len; |
OM_uint32 status; |
OM_uint32 status; |
u_int slen; |
int r; |
|
|
if (authctxt == NULL) |
if (authctxt == NULL) |
fatal("input_gssapi_response: no authentication context"); |
fatal("input_gssapi_response: no authentication context"); |
|
|
recv_tok.value = packet_get_string(&slen); |
if ((r = sshpkt_get_string(ssh, &p, &len)) != 0 || |
recv_tok.length = slen; /* safe typecast */ |
(r = sshpkt_get_end(ssh)) != 0) |
|
goto out; |
|
|
packet_check_eom(); |
recv_tok.value = p; |
|
recv_tok.length = len; |
status = process_gssapi_token(ssh, &recv_tok); |
status = process_gssapi_token(ssh, &recv_tok); |
|
|
free(recv_tok.value); |
/* Start again with the next method in the list */ |
|
|
if (GSS_ERROR(status)) { |
if (GSS_ERROR(status)) { |
/* Start again with the next method in the list */ |
|
userauth(authctxt, NULL); |
userauth(authctxt, NULL); |
return 0; |
/* ok */ |
} |
} |
return 0; |
r = 0; |
|
out: |
|
free(p); |
|
return r; |
} |
} |
|
|
/* ARGSUSED */ |
/* ARGSUSED */ |
|
|
gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; |
gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; |
gss_buffer_desc recv_tok; |
gss_buffer_desc recv_tok; |
OM_uint32 ms; |
OM_uint32 ms; |
u_int len; |
u_char *p = NULL; |
|
size_t len; |
|
int r; |
|
|
if (authctxt == NULL) |
if (authctxt == NULL) |
fatal("input_gssapi_response: no authentication context"); |
fatal("input_gssapi_response: no authentication context"); |
gssctxt = authctxt->methoddata; |
gssctxt = authctxt->methoddata; |
|
|
recv_tok.value = packet_get_string(&len); |
if ((r = sshpkt_get_string(ssh, &p, &len)) != 0 || |
recv_tok.length = len; |
(r = sshpkt_get_end(ssh)) != 0) { |
|
free(p); |
|
return r; |
|
} |
|
|
packet_check_eom(); |
|
|
|
/* Stick it into GSSAPI and see what it says */ |
/* Stick it into GSSAPI and see what it says */ |
|
recv_tok.value = p; |
|
recv_tok.length = len; |
(void)ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, |
(void)ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, |
&recv_tok, &send_tok, NULL); |
&recv_tok, &send_tok, NULL); |
|
free(p); |
free(recv_tok.value); |
|
gss_release_buffer(&ms, &send_tok); |
gss_release_buffer(&ms, &send_tok); |
|
|
/* Server will be returning a failed packet after this one */ |
/* Server will be returning a failed packet after this one */ |
|
|
int |
int |
input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh) |
input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh) |
{ |
{ |
char *msg; |
char *msg = NULL; |
char *lang; |
char *lang = NULL; |
|
int r; |
|
|
/* maj */(void)packet_get_int(); |
if ((r = sshpkt_get_u32(ssh, NULL)) != 0 || /* maj */ |
/* min */(void)packet_get_int(); |
(r = sshpkt_get_u32(ssh, NULL)) != 0 || /* min */ |
msg=packet_get_string(NULL); |
(r = sshpkt_get_cstring(ssh, &msg, NULL)) != 0 || |
lang=packet_get_string(NULL); |
(r = sshpkt_get_cstring(ssh, &lang, NULL)) != 0) |
|
goto out; |
packet_check_eom(); |
r = sshpkt_get_end(ssh); |
|
|
debug("Server GSSAPI Error:\n%s", msg); |
debug("Server GSSAPI Error:\n%s", msg); |
|
out: |
free(msg); |
free(msg); |
free(lang); |
free(lang); |
return 0; |
return r; |
} |
} |
#endif /* GSSAPI */ |
#endif /* GSSAPI */ |
|
|
int |
int |
userauth_none(Authctxt *authctxt) |
userauth_none(Authctxt *authctxt) |
{ |
{ |
|
struct ssh *ssh = active_state; /* XXX */ |
|
int r; |
|
|
/* initial userauth request */ |
/* initial userauth request */ |
packet_start(SSH2_MSG_USERAUTH_REQUEST); |
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || |
packet_put_cstring(authctxt->server_user); |
(r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || |
packet_put_cstring(authctxt->service); |
(r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || |
packet_put_cstring(authctxt->method->name); |
(r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || |
packet_send(); |
(r = sshpkt_send(ssh)) != 0) |
|
fatal("%s: %s", __func__, ssh_err(r)); |
return 1; |
return 1; |
} |
} |
|
|
int |
int |
userauth_passwd(Authctxt *authctxt) |
userauth_passwd(Authctxt *authctxt) |
{ |
{ |
|
struct ssh *ssh = active_state; /* XXX */ |
static int attempt = 0; |
static int attempt = 0; |
char prompt[256]; |
char prompt[256]; |
char *password; |
char *password; |
const char *host = options.host_key_alias ? options.host_key_alias : |
const char *host = options.host_key_alias ? options.host_key_alias : |
authctxt->host; |
authctxt->host; |
|
int r; |
|
|
if (attempt++ >= options.number_of_password_prompts) |
if (attempt++ >= options.number_of_password_prompts) |
return 0; |
return 0; |
|
|
snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ", |
snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ", |
authctxt->server_user, host); |
authctxt->server_user, host); |
password = read_passphrase(prompt, 0); |
password = read_passphrase(prompt, 0); |
packet_start(SSH2_MSG_USERAUTH_REQUEST); |
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || |
packet_put_cstring(authctxt->server_user); |
(r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || |
packet_put_cstring(authctxt->service); |
(r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || |
packet_put_cstring(authctxt->method->name); |
(r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || |
packet_put_char(0); |
(r = sshpkt_put_u8(ssh, 0)) != 0 || |
packet_put_cstring(password); |
(r = sshpkt_put_cstring(ssh, password)) != 0 || |
explicit_bzero(password, strlen(password)); |
(r = sshpkt_add_padding(ssh, 64)) != 0 || |
free(password); |
(r = sshpkt_send(ssh)) != 0) |
packet_add_padding(64); |
fatal("%s: %s", __func__, ssh_err(r)); |
packet_send(); |
|
|
|
dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, |
if (password) |
|
freezero(password, strlen(password)); |
|
|
|
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, |
&input_userauth_passwd_changereq); |
&input_userauth_passwd_changereq); |
|
|
return 1; |
return 1; |
|
|
input_userauth_passwd_changereq(int type, u_int32_t seqnr, struct ssh *ssh) |
input_userauth_passwd_changereq(int type, u_int32_t seqnr, struct ssh *ssh) |
{ |
{ |
Authctxt *authctxt = ssh->authctxt; |
Authctxt *authctxt = ssh->authctxt; |
char *info, *lang, *password = NULL, *retype = NULL; |
char *info = NULL, *lang = NULL, *password = NULL, *retype = NULL; |
char prompt[256]; |
char prompt[256]; |
const char *host; |
const char *host; |
|
int r; |
|
|
debug2("input_userauth_passwd_changereq"); |
debug2("input_userauth_passwd_changereq"); |
|
|
|
|
"no authentication context"); |
"no authentication context"); |
host = options.host_key_alias ? options.host_key_alias : authctxt->host; |
host = options.host_key_alias ? options.host_key_alias : authctxt->host; |
|
|
info = packet_get_string(NULL); |
if ((r = sshpkt_get_cstring(ssh, &info, NULL)) != 0 || |
lang = packet_get_string(NULL); |
(r = sshpkt_get_cstring(ssh, &lang, NULL)) != 0) |
|
goto out; |
if (strlen(info) > 0) |
if (strlen(info) > 0) |
logit("%s", info); |
logit("%s", info); |
free(info); |
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || |
free(lang); |
(r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || |
packet_start(SSH2_MSG_USERAUTH_REQUEST); |
(r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || |
packet_put_cstring(authctxt->server_user); |
(r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || |
packet_put_cstring(authctxt->service); |
(r = sshpkt_put_u8(ssh, 1)) != 0) /* additional info */ |
packet_put_cstring(authctxt->method->name); |
goto out; |
packet_put_char(1); /* additional info */ |
|
snprintf(prompt, sizeof(prompt), |
snprintf(prompt, sizeof(prompt), |
"Enter %.30s@%.128s's old password: ", |
"Enter %.30s@%.128s's old password: ", |
authctxt->server_user, host); |
authctxt->server_user, host); |
password = read_passphrase(prompt, 0); |
password = read_passphrase(prompt, 0); |
packet_put_cstring(password); |
if ((r = sshpkt_put_cstring(ssh, password)) != 0) |
explicit_bzero(password, strlen(password)); |
goto out; |
free(password); |
|
|
freezero(password, strlen(password)); |
password = NULL; |
password = NULL; |
while (password == NULL) { |
while (password == NULL) { |
snprintf(prompt, sizeof(prompt), |
snprintf(prompt, sizeof(prompt), |
|
|
password = read_passphrase(prompt, RP_ALLOW_EOF); |
password = read_passphrase(prompt, RP_ALLOW_EOF); |
if (password == NULL) { |
if (password == NULL) { |
/* bail out */ |
/* bail out */ |
return 0; |
r = 0; |
|
goto out; |
} |
} |
snprintf(prompt, sizeof(prompt), |
snprintf(prompt, sizeof(prompt), |
"Retype %.30s@%.128s's new password: ", |
"Retype %.30s@%.128s's new password: ", |
authctxt->server_user, host); |
authctxt->server_user, host); |
retype = read_passphrase(prompt, 0); |
retype = read_passphrase(prompt, 0); |
if (strcmp(password, retype) != 0) { |
if (strcmp(password, retype) != 0) { |
explicit_bzero(password, strlen(password)); |
freezero(password, strlen(password)); |
free(password); |
|
logit("Mismatch; try again, EOF to quit."); |
logit("Mismatch; try again, EOF to quit."); |
password = NULL; |
password = NULL; |
} |
} |
explicit_bzero(retype, strlen(retype)); |
freezero(retype, strlen(retype)); |
free(retype); |
|
} |
} |
packet_put_cstring(password); |
if ((r = sshpkt_put_cstring(ssh, password)) != 0 || |
explicit_bzero(password, strlen(password)); |
(r = sshpkt_add_padding(ssh, 64)) != 0 || |
free(password); |
(r = sshpkt_send(ssh)) != 0) |
packet_add_padding(64); |
goto out; |
packet_send(); |
|
|
|
dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, |
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, |
&input_userauth_passwd_changereq); |
&input_userauth_passwd_changereq); |
return 0; |
r = 0; |
|
out: |
|
if (password) |
|
freezero(password, strlen(password)); |
|
free(info); |
|
free(lang); |
|
return r; |
} |
} |
|
|
/* |
/* |
|
|
__func__, ssh_err(r)); |
__func__, ssh_err(r)); |
} |
} |
} |
} |
skip = buffer_len(b); |
skip = sshbuf_len(b); |
if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || |
if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || |
(r = sshbuf_put_cstring(b, authctxt->server_user)) != 0 || |
(r = sshbuf_put_cstring(b, authctxt->server_user)) != 0 || |
(r = sshbuf_put_cstring(b, authctxt->service)) != 0 || |
(r = sshbuf_put_cstring(b, authctxt->service)) != 0 || |
|
|
send_pubkey_test(struct ssh *ssh, Authctxt *authctxt, Identity *id) |
send_pubkey_test(struct ssh *ssh, Authctxt *authctxt, Identity *id) |
{ |
{ |
u_char *blob = NULL; |
u_char *blob = NULL; |
u_int bloblen, have_sig = 0; |
|
char *alg = NULL; |
char *alg = NULL; |
int sent = 0; |
size_t bloblen; |
|
u_int have_sig = 0; |
|
int sent = 0, r; |
|
|
if ((alg = key_sig_algorithm(ssh, id->key)) == NULL) { |
if ((alg = key_sig_algorithm(ssh, id->key)) == NULL) { |
debug("%s: no mutual signature algorithm", __func__); |
debug("%s: no mutual signature algorithm", __func__); |
goto out; |
goto out; |
} |
} |
|
|
if (key_to_blob(id->key, &blob, &bloblen) == 0) { |
if ((r = sshkey_to_blob(id->key, &blob, &bloblen)) != 0) { |
/* we cannot handle this key */ |
/* we cannot handle this key */ |
debug3("%s: cannot handle key", __func__); |
debug3("%s: cannot handle key", __func__); |
goto out; |
goto out; |
} |
} |
/* register callback for USERAUTH_PK_OK message */ |
/* register callback for USERAUTH_PK_OK message */ |
dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok); |
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok); |
|
|
packet_start(SSH2_MSG_USERAUTH_REQUEST); |
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || |
packet_put_cstring(authctxt->server_user); |
(r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || |
packet_put_cstring(authctxt->service); |
(r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || |
packet_put_cstring(authctxt->method->name); |
(r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || |
packet_put_char(have_sig); |
(r = sshpkt_put_u8(ssh, have_sig)) != 0 || |
packet_put_cstring(alg); |
(r = sshpkt_put_cstring(ssh, alg)) != 0 || |
packet_put_string(blob, bloblen); |
(r = sshpkt_put_string(ssh, blob, bloblen)) != 0 || |
packet_send(); |
(r = sshpkt_send(ssh)) != 0) |
/* success */ |
fatal("%s: %s", __func__, ssh_err(r)); |
sent = 1; |
sent = 1; |
out: |
|
|
out: |
free(alg); |
free(alg); |
free(blob); |
free(blob); |
return sent; |
return sent; |
|
|
!(id->key && id->isprivate)) |
!(id->key && id->isprivate)) |
maybe_add_key_to_agent(id->filename, private, comment, |
maybe_add_key_to_agent(id->filename, private, comment, |
passphrase); |
passphrase); |
if (i > 0) { |
if (i > 0) |
explicit_bzero(passphrase, strlen(passphrase)); |
freezero(passphrase, strlen(passphrase)); |
free(passphrase); |
|
} |
|
free(comment); |
free(comment); |
if (private != NULL || quit) |
if (private != NULL || quit) |
break; |
break; |
|
|
/* list of certificates specified by user */ |
/* list of certificates specified by user */ |
for (i = 0; i < options.num_certificate_files; i++) { |
for (i = 0; i < options.num_certificate_files; i++) { |
key = options.certificates[i]; |
key = options.certificates[i]; |
if (!key_is_cert(key) || key->cert == NULL || |
if (!sshkey_is_cert(key) || key->cert == NULL || |
key->cert->type != SSH2_CERT_TYPE_USER) |
key->cert->type != SSH2_CERT_TYPE_USER) |
continue; |
continue; |
id = xcalloc(1, sizeof(*id)); |
id = xcalloc(1, sizeof(*id)); |
|
|
/* If IdentitiesOnly set and key not found then don't use it */ |
/* If IdentitiesOnly set and key not found then don't use it */ |
if (!found && options.identities_only) { |
if (!found && options.identities_only) { |
TAILQ_REMOVE(&files, id, next); |
TAILQ_REMOVE(&files, id, next); |
explicit_bzero(id, sizeof(*id)); |
freezero(id, sizeof(*id)); |
free(id); |
|
} |
} |
} |
} |
/* append remaining keys from the config file */ |
/* append remaining keys from the config file */ |
|
|
sent = sign_and_send_pubkey(ssh, |
sent = sign_and_send_pubkey(ssh, |
authctxt, id); |
authctxt, id); |
} |
} |
key_free(id->key); |
sshkey_free(id->key); |
id->key = NULL; |
id->key = NULL; |
id->isprivate = 0; |
id->isprivate = 0; |
} |
} |
|
|
int |
int |
userauth_kbdint(Authctxt *authctxt) |
userauth_kbdint(Authctxt *authctxt) |
{ |
{ |
|
struct ssh *ssh = active_state; /* XXX */ |
static int attempt = 0; |
static int attempt = 0; |
|
int r; |
|
|
if (attempt++ >= options.number_of_password_prompts) |
if (attempt++ >= options.number_of_password_prompts) |
return 0; |
return 0; |
/* disable if no SSH2_MSG_USERAUTH_INFO_REQUEST has been seen */ |
/* disable if no SSH2_MSG_USERAUTH_INFO_REQUEST has been seen */ |
if (attempt > 1 && !authctxt->info_req_seen) { |
if (attempt > 1 && !authctxt->info_req_seen) { |
debug3("userauth_kbdint: disable: no info_req_seen"); |
debug3("userauth_kbdint: disable: no info_req_seen"); |
dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL); |
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_INFO_REQUEST, NULL); |
return 0; |
return 0; |
} |
} |
|
|
debug2("userauth_kbdint"); |
debug2("userauth_kbdint"); |
packet_start(SSH2_MSG_USERAUTH_REQUEST); |
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || |
packet_put_cstring(authctxt->server_user); |
(r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || |
packet_put_cstring(authctxt->service); |
(r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || |
packet_put_cstring(authctxt->method->name); |
(r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || |
packet_put_cstring(""); /* lang */ |
(r = sshpkt_put_cstring(ssh, "")) != 0 || /* lang */ |
packet_put_cstring(options.kbd_interactive_devices ? |
(r = sshpkt_put_cstring(ssh, options.kbd_interactive_devices ? |
options.kbd_interactive_devices : ""); |
options.kbd_interactive_devices : "")) != 0 || |
packet_send(); |
(r = sshpkt_send(ssh)) != 0) |
|
fatal("%s: %s", __func__, ssh_err(r)); |
|
|
dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req); |
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req); |
return 1; |
return 1; |
} |
} |
|
|
|
|
input_userauth_info_req(int type, u_int32_t seq, struct ssh *ssh) |
input_userauth_info_req(int type, u_int32_t seq, struct ssh *ssh) |
{ |
{ |
Authctxt *authctxt = ssh->authctxt; |
Authctxt *authctxt = ssh->authctxt; |
char *name, *inst, *lang, *prompt, *response; |
char *name = NULL, *inst = NULL, *lang = NULL, *prompt = NULL; |
|
char *response = NULL; |
|
u_char echo = 0; |
u_int num_prompts, i; |
u_int num_prompts, i; |
int echo = 0; |
int r; |
|
|
debug2("input_userauth_info_req"); |
debug2("input_userauth_info_req"); |
|
|
|
|
|
|
authctxt->info_req_seen = 1; |
authctxt->info_req_seen = 1; |
|
|
name = packet_get_string(NULL); |
if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0 || |
inst = packet_get_string(NULL); |
(r = sshpkt_get_cstring(ssh, &inst, NULL)) != 0 || |
lang = packet_get_string(NULL); |
(r = sshpkt_get_cstring(ssh, &lang, NULL)) != 0) |
|
goto out; |
if (strlen(name) > 0) |
if (strlen(name) > 0) |
logit("%s", name); |
logit("%s", name); |
if (strlen(inst) > 0) |
if (strlen(inst) > 0) |
logit("%s", inst); |
logit("%s", inst); |
free(name); |
|
free(inst); |
|
free(lang); |
|
|
|
num_prompts = packet_get_int(); |
if ((r = sshpkt_get_u32(ssh, &num_prompts)) != 0) |
|
goto out; |
/* |
/* |
* Begin to build info response packet based on prompts requested. |
* Begin to build info response packet based on prompts requested. |
* We commit to providing the correct number of responses, so if |
* We commit to providing the correct number of responses, so if |
* further on we run into a problem that prevents this, we have to |
* further on we run into a problem that prevents this, we have to |
* be sure and clean this up and send a correct error response. |
* be sure and clean this up and send a correct error response. |
*/ |
*/ |
packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE); |
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_INFO_RESPONSE)) != 0 || |
packet_put_int(num_prompts); |
(r = sshpkt_put_u32(ssh, num_prompts)) != 0) |
|
goto out; |
|
|
debug2("input_userauth_info_req: num_prompts %d", num_prompts); |
debug2("input_userauth_info_req: num_prompts %d", num_prompts); |
for (i = 0; i < num_prompts; i++) { |
for (i = 0; i < num_prompts; i++) { |
prompt = packet_get_string(NULL); |
if ((r = sshpkt_get_cstring(ssh, &prompt, NULL)) != 0 || |
echo = packet_get_char(); |
(r = sshpkt_get_u8(ssh, &echo)) != 0) |
|
goto out; |
response = read_passphrase(prompt, echo ? RP_ECHO : 0); |
response = read_passphrase(prompt, echo ? RP_ECHO : 0); |
|
if ((r = sshpkt_put_cstring(ssh, response)) != 0) |
packet_put_cstring(response); |
goto out; |
explicit_bzero(response, strlen(response)); |
freezero(response, strlen(response)); |
free(response); |
|
free(prompt); |
free(prompt); |
|
response = prompt = NULL; |
} |
} |
packet_check_eom(); /* done with parsing incoming message. */ |
/* done with parsing incoming message. */ |
|
if ((r = sshpkt_get_end(ssh)) != 0 || |
packet_add_padding(64); |
(r = sshpkt_add_padding(ssh, 64)) != 0) |
packet_send(); |
goto out; |
return 0; |
r = sshpkt_send(ssh); |
|
out: |
|
if (response) |
|
freezero(response, strlen(response)); |
|
free(prompt); |
|
free(name); |
|
free(inst); |
|
free(lang); |
|
return r; |
} |
} |
|
|
static int |
static int |
|
|
success = 1; |
success = 1; |
|
|
out: |
out: |
if (sig != NULL) { |
if (sig != NULL) |
explicit_bzero(sig, siglen); |
freezero(sig, siglen); |
free(sig); |
|
} |
|
free(keyblob); |
free(keyblob); |
free(lname); |
free(lname); |
free(fp); |
free(fp); |
|
|
authmethods_get(void) |
authmethods_get(void) |
{ |
{ |
Authmethod *method = NULL; |
Authmethod *method = NULL; |
Buffer b; |
struct sshbuf *b; |
char *list; |
char *list; |
|
int r; |
|
|
buffer_init(&b); |
if ((b = sshbuf_new()) == NULL) |
|
fatal("%s: sshbuf_new failed", __func__); |
for (method = authmethods; method->name != NULL; method++) { |
for (method = authmethods; method->name != NULL; method++) { |
if (authmethod_is_enabled(method)) { |
if (authmethod_is_enabled(method)) { |
if (buffer_len(&b) > 0) |
if ((r = sshbuf_putf(b, "%s%s", |
buffer_append(&b, ",", 1); |
sshbuf_len(b) ? "," : "", method->name)) != 0) |
buffer_append(&b, method->name, strlen(method->name)); |
fatal("%s: buffer error: %s", |
|
__func__, ssh_err(r)); |
} |
} |
} |
} |
if ((list = sshbuf_dup_string(&b)) == NULL) |
if ((list = sshbuf_dup_string(b)) == NULL) |
fatal("%s: sshbuf_dup_string failed", __func__); |
fatal("%s: sshbuf_dup_string failed", __func__); |
buffer_free(&b); |
sshbuf_free(b); |
return list; |
return list; |
} |
} |
|
|