version 1.27.2.3, 2001/03/21 19:46:31 |
version 1.27.2.4, 2001/05/07 21:09:37 |
|
|
#include "sshconnect.h" |
#include "sshconnect.h" |
#include "authfile.h" |
#include "authfile.h" |
#include "cli.h" |
#include "cli.h" |
#include "dispatch.h" |
#include "dh.h" |
#include "authfd.h" |
#include "authfd.h" |
#include "log.h" |
#include "log.h" |
#include "readconf.h" |
#include "readconf.h" |
#include "readpass.h" |
#include "readpass.h" |
#include "match.h" |
#include "match.h" |
|
#include "dispatch.h" |
|
#include "canohost.h" |
|
|
void ssh_dh1_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *); |
|
void ssh_dhgex_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *); |
|
|
|
/* import */ |
/* import */ |
extern char *client_version_string; |
extern char *client_version_string; |
extern char *server_version_string; |
extern char *server_version_string; |
|
|
u_char *session_id2 = NULL; |
u_char *session_id2 = NULL; |
int session_id2_len = 0; |
int session_id2_len = 0; |
|
|
|
char *xxx_host; |
|
struct sockaddr *xxx_hostaddr; |
|
|
|
Kex *xxx_kex = NULL; |
|
|
|
int |
|
check_host_key_callback(Key *hostkey) |
|
{ |
|
check_host_key(xxx_host, xxx_hostaddr, hostkey, |
|
options.user_hostfile2, options.system_hostfile2); |
|
return 0; |
|
} |
|
|
void |
void |
ssh_kex2(char *host, struct sockaddr *hostaddr) |
ssh_kex2(char *host, struct sockaddr *hostaddr) |
{ |
{ |
int i, plen; |
|
Kex *kex; |
Kex *kex; |
Buffer *client_kexinit, *server_kexinit; |
|
char *sprop[PROPOSAL_MAX]; |
|
|
|
|
xxx_host = host; |
|
xxx_hostaddr = hostaddr; |
|
|
if (options.ciphers == (char *)-1) { |
if (options.ciphers == (char *)-1) { |
log("No valid ciphers for protocol version 2 given, using defaults."); |
log("No valid ciphers for protocol version 2 given, using defaults."); |
options.ciphers = NULL; |
options.ciphers = NULL; |
|
|
myproposal[PROPOSAL_ENC_ALGS_CTOS] = |
myproposal[PROPOSAL_ENC_ALGS_CTOS] = |
myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; |
myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; |
} |
} |
|
myproposal[PROPOSAL_ENC_ALGS_CTOS] = |
|
compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); |
|
myproposal[PROPOSAL_ENC_ALGS_STOC] = |
|
compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]); |
if (options.compression) { |
if (options.compression) { |
myproposal[PROPOSAL_COMP_ALGS_CTOS] = |
myproposal[PROPOSAL_COMP_ALGS_CTOS] = |
myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib"; |
myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib"; |
|
|
myproposal[PROPOSAL_MAC_ALGS_CTOS] = |
myproposal[PROPOSAL_MAC_ALGS_CTOS] = |
myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; |
myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; |
} |
} |
|
if (options.hostkeyalgorithms != NULL) |
|
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = |
|
options.hostkeyalgorithms; |
|
|
/* buffers with raw kexinit messages */ |
/* start key exchange */ |
server_kexinit = xmalloc(sizeof(*server_kexinit)); |
kex = kex_setup(myproposal); |
buffer_init(server_kexinit); |
kex->client_version_string=client_version_string; |
client_kexinit = kex_init(myproposal); |
kex->server_version_string=server_version_string; |
|
kex->check_host_key=&check_host_key_callback; |
|
|
/* algorithm negotiation */ |
xxx_kex = kex; |
kex_exchange_kexinit(client_kexinit, server_kexinit, sprop); |
|
kex = kex_choose_conf(myproposal, sprop, 0); |
|
for (i = 0; i < PROPOSAL_MAX; i++) |
|
xfree(sprop[i]); |
|
|
|
/* server authentication and session key agreement */ |
dispatch_run(DISPATCH_BLOCK, &kex->done, kex); |
switch(kex->kex_type) { |
|
case DH_GRP1_SHA1: |
|
ssh_dh1_client(kex, host, hostaddr, |
|
client_kexinit, server_kexinit); |
|
break; |
|
case DH_GEX_SHA1: |
|
ssh_dhgex_client(kex, host, hostaddr, client_kexinit, |
|
server_kexinit); |
|
break; |
|
default: |
|
fatal("Unsupported key exchange %d", kex->kex_type); |
|
} |
|
|
|
buffer_free(client_kexinit); |
session_id2 = kex->session_id; |
buffer_free(server_kexinit); |
session_id2_len = kex->session_id_len; |
xfree(client_kexinit); |
|
xfree(server_kexinit); |
|
|
|
debug("Wait SSH2_MSG_NEWKEYS."); |
|
packet_read_expect(&plen, SSH2_MSG_NEWKEYS); |
|
packet_done(); |
|
debug("GOT SSH2_MSG_NEWKEYS."); |
|
|
|
debug("send SSH2_MSG_NEWKEYS."); |
|
packet_start(SSH2_MSG_NEWKEYS); |
|
packet_send(); |
|
packet_write_wait(); |
|
debug("done: send SSH2_MSG_NEWKEYS."); |
|
|
|
#ifdef DEBUG_KEXDH |
#ifdef DEBUG_KEXDH |
/* send 1st encrypted/maced/compressed message */ |
/* send 1st encrypted/maced/compressed message */ |
packet_start(SSH2_MSG_IGNORE); |
packet_start(SSH2_MSG_IGNORE); |
|
|
packet_send(); |
packet_send(); |
packet_write_wait(); |
packet_write_wait(); |
#endif |
#endif |
debug("done: KEX2."); |
debug("done: ssh_kex2."); |
} |
} |
|
|
/* diffie-hellman-group1-sha1 */ |
|
|
|
void |
|
ssh_dh1_client(Kex *kex, char *host, struct sockaddr *hostaddr, |
|
Buffer *client_kexinit, Buffer *server_kexinit) |
|
{ |
|
#ifdef DEBUG_KEXDH |
|
int i; |
|
#endif |
|
int plen, dlen; |
|
u_int klen, kout; |
|
char *signature = NULL; |
|
u_int slen; |
|
char *server_host_key_blob = NULL; |
|
Key *server_host_key; |
|
u_int sbloblen; |
|
DH *dh; |
|
BIGNUM *dh_server_pub = 0; |
|
BIGNUM *shared_secret = 0; |
|
u_char *kbuf; |
|
u_char *hash; |
|
|
|
debug("Sending SSH2_MSG_KEXDH_INIT."); |
|
/* generate and send 'e', client DH public key */ |
|
dh = dh_new_group1(); |
|
dh_gen_key(dh, kex->we_need * 8); |
|
packet_start(SSH2_MSG_KEXDH_INIT); |
|
packet_put_bignum2(dh->pub_key); |
|
packet_send(); |
|
packet_write_wait(); |
|
|
|
#ifdef DEBUG_KEXDH |
|
fprintf(stderr, "\np= "); |
|
BN_print_fp(stderr, dh->p); |
|
fprintf(stderr, "\ng= "); |
|
BN_print_fp(stderr, dh->g); |
|
fprintf(stderr, "\npub= "); |
|
BN_print_fp(stderr, dh->pub_key); |
|
fprintf(stderr, "\n"); |
|
DHparams_print_fp(stderr, dh); |
|
#endif |
|
|
|
debug("Wait SSH2_MSG_KEXDH_REPLY."); |
|
|
|
packet_read_expect(&plen, SSH2_MSG_KEXDH_REPLY); |
|
|
|
debug("Got SSH2_MSG_KEXDH_REPLY."); |
|
|
|
/* key, cert */ |
|
server_host_key_blob = packet_get_string(&sbloblen); |
|
server_host_key = key_from_blob(server_host_key_blob, sbloblen); |
|
if (server_host_key == NULL) |
|
fatal("cannot decode server_host_key_blob"); |
|
|
|
check_host_key(host, hostaddr, server_host_key, |
|
options.user_hostfile2, options.system_hostfile2); |
|
|
|
/* DH paramter f, server public DH key */ |
|
dh_server_pub = BN_new(); |
|
if (dh_server_pub == NULL) |
|
fatal("dh_server_pub == NULL"); |
|
packet_get_bignum2(dh_server_pub, &dlen); |
|
|
|
#ifdef DEBUG_KEXDH |
|
fprintf(stderr, "\ndh_server_pub= "); |
|
BN_print_fp(stderr, dh_server_pub); |
|
fprintf(stderr, "\n"); |
|
debug("bits %d", BN_num_bits(dh_server_pub)); |
|
#endif |
|
|
|
/* signed H */ |
|
signature = packet_get_string(&slen); |
|
packet_done(); |
|
|
|
if (!dh_pub_is_valid(dh, dh_server_pub)) |
|
packet_disconnect("bad server public DH value"); |
|
|
|
klen = DH_size(dh); |
|
kbuf = xmalloc(klen); |
|
kout = DH_compute_key(kbuf, dh_server_pub, dh); |
|
#ifdef DEBUG_KEXDH |
|
debug("shared secret: len %d/%d", klen, kout); |
|
fprintf(stderr, "shared secret == "); |
|
for (i = 0; i< kout; i++) |
|
fprintf(stderr, "%02x", (kbuf[i])&0xff); |
|
fprintf(stderr, "\n"); |
|
#endif |
|
shared_secret = BN_new(); |
|
|
|
BN_bin2bn(kbuf, kout, shared_secret); |
|
memset(kbuf, 0, klen); |
|
xfree(kbuf); |
|
|
|
/* calc and verify H */ |
|
hash = kex_hash( |
|
client_version_string, |
|
server_version_string, |
|
buffer_ptr(client_kexinit), buffer_len(client_kexinit), |
|
buffer_ptr(server_kexinit), buffer_len(server_kexinit), |
|
server_host_key_blob, sbloblen, |
|
dh->pub_key, |
|
dh_server_pub, |
|
shared_secret |
|
); |
|
xfree(server_host_key_blob); |
|
DH_free(dh); |
|
BN_free(dh_server_pub); |
|
#ifdef DEBUG_KEXDH |
|
fprintf(stderr, "hash == "); |
|
for (i = 0; i< 20; i++) |
|
fprintf(stderr, "%02x", (hash[i])&0xff); |
|
fprintf(stderr, "\n"); |
|
#endif |
|
if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1) |
|
fatal("key_verify failed for server_host_key"); |
|
key_free(server_host_key); |
|
xfree(signature); |
|
|
|
kex_derive_keys(kex, hash, shared_secret); |
|
BN_clear_free(shared_secret); |
|
packet_set_kex(kex); |
|
|
|
/* save session id */ |
|
session_id2_len = 20; |
|
session_id2 = xmalloc(session_id2_len); |
|
memcpy(session_id2, hash, session_id2_len); |
|
} |
|
|
|
/* diffie-hellman-group-exchange-sha1 */ |
|
|
|
/* |
/* |
* Estimates the group order for a Diffie-Hellman group that has an |
|
* attack complexity approximately the same as O(2**bits). Estimate |
|
* with: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3))) |
|
*/ |
|
|
|
int |
|
dh_estimate(int bits) |
|
{ |
|
|
|
if (bits < 64) |
|
return (512); /* O(2**63) */ |
|
if (bits < 128) |
|
return (1024); /* O(2**86) */ |
|
if (bits < 192) |
|
return (2048); /* O(2**116) */ |
|
return (4096); /* O(2**156) */ |
|
} |
|
|
|
void |
|
ssh_dhgex_client(Kex *kex, char *host, struct sockaddr *hostaddr, |
|
Buffer *client_kexinit, Buffer *server_kexinit) |
|
{ |
|
#ifdef DEBUG_KEXDH |
|
int i; |
|
#endif |
|
int plen, dlen; |
|
u_int klen, kout; |
|
char *signature = NULL; |
|
u_int slen, nbits; |
|
char *server_host_key_blob = NULL; |
|
Key *server_host_key; |
|
u_int sbloblen; |
|
DH *dh; |
|
BIGNUM *dh_server_pub = 0; |
|
BIGNUM *shared_secret = 0; |
|
BIGNUM *p = 0, *g = 0; |
|
u_char *kbuf; |
|
u_char *hash; |
|
|
|
nbits = dh_estimate(kex->we_need * 8); |
|
|
|
debug("Sending SSH2_MSG_KEX_DH_GEX_REQUEST."); |
|
packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST); |
|
packet_put_int(nbits); |
|
packet_send(); |
|
packet_write_wait(); |
|
|
|
#ifdef DEBUG_KEXDH |
|
fprintf(stderr, "\nnbits = %d", nbits); |
|
#endif |
|
|
|
debug("Wait SSH2_MSG_KEX_DH_GEX_GROUP."); |
|
|
|
packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_GROUP); |
|
|
|
debug("Got SSH2_MSG_KEX_DH_GEX_GROUP."); |
|
|
|
if ((p = BN_new()) == NULL) |
|
fatal("BN_new"); |
|
packet_get_bignum2(p, &dlen); |
|
if ((g = BN_new()) == NULL) |
|
fatal("BN_new"); |
|
packet_get_bignum2(g, &dlen); |
|
dh = dh_new_group(g, p); |
|
|
|
dh_gen_key(dh, kex->we_need * 8); |
|
|
|
#ifdef DEBUG_KEXDH |
|
fprintf(stderr, "\np= "); |
|
BN_print_fp(stderr, dh->p); |
|
fprintf(stderr, "\ng= "); |
|
BN_print_fp(stderr, dh->g); |
|
fprintf(stderr, "\npub= "); |
|
BN_print_fp(stderr, dh->pub_key); |
|
fprintf(stderr, "\n"); |
|
DHparams_print_fp(stderr, dh); |
|
#endif |
|
|
|
debug("Sending SSH2_MSG_KEX_DH_GEX_INIT."); |
|
/* generate and send 'e', client DH public key */ |
|
packet_start(SSH2_MSG_KEX_DH_GEX_INIT); |
|
packet_put_bignum2(dh->pub_key); |
|
packet_send(); |
|
packet_write_wait(); |
|
|
|
debug("Wait SSH2_MSG_KEX_DH_GEX_REPLY."); |
|
|
|
packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_REPLY); |
|
|
|
debug("Got SSH2_MSG_KEXDH_REPLY."); |
|
|
|
/* key, cert */ |
|
server_host_key_blob = packet_get_string(&sbloblen); |
|
server_host_key = key_from_blob(server_host_key_blob, sbloblen); |
|
if (server_host_key == NULL) |
|
fatal("cannot decode server_host_key_blob"); |
|
|
|
check_host_key(host, hostaddr, server_host_key, |
|
options.user_hostfile2, options.system_hostfile2); |
|
|
|
/* DH paramter f, server public DH key */ |
|
dh_server_pub = BN_new(); |
|
if (dh_server_pub == NULL) |
|
fatal("dh_server_pub == NULL"); |
|
packet_get_bignum2(dh_server_pub, &dlen); |
|
|
|
#ifdef DEBUG_KEXDH |
|
fprintf(stderr, "\ndh_server_pub= "); |
|
BN_print_fp(stderr, dh_server_pub); |
|
fprintf(stderr, "\n"); |
|
debug("bits %d", BN_num_bits(dh_server_pub)); |
|
#endif |
|
|
|
/* signed H */ |
|
signature = packet_get_string(&slen); |
|
packet_done(); |
|
|
|
if (!dh_pub_is_valid(dh, dh_server_pub)) |
|
packet_disconnect("bad server public DH value"); |
|
|
|
klen = DH_size(dh); |
|
kbuf = xmalloc(klen); |
|
kout = DH_compute_key(kbuf, dh_server_pub, dh); |
|
#ifdef DEBUG_KEXDH |
|
debug("shared secret: len %d/%d", klen, kout); |
|
fprintf(stderr, "shared secret == "); |
|
for (i = 0; i< kout; i++) |
|
fprintf(stderr, "%02x", (kbuf[i])&0xff); |
|
fprintf(stderr, "\n"); |
|
#endif |
|
shared_secret = BN_new(); |
|
|
|
BN_bin2bn(kbuf, kout, shared_secret); |
|
memset(kbuf, 0, klen); |
|
xfree(kbuf); |
|
|
|
/* calc and verify H */ |
|
hash = kex_hash_gex( |
|
client_version_string, |
|
server_version_string, |
|
buffer_ptr(client_kexinit), buffer_len(client_kexinit), |
|
buffer_ptr(server_kexinit), buffer_len(server_kexinit), |
|
server_host_key_blob, sbloblen, |
|
nbits, dh->p, dh->g, |
|
dh->pub_key, |
|
dh_server_pub, |
|
shared_secret |
|
); |
|
xfree(server_host_key_blob); |
|
DH_free(dh); |
|
BN_free(dh_server_pub); |
|
#ifdef DEBUG_KEXDH |
|
fprintf(stderr, "hash == "); |
|
for (i = 0; i< 20; i++) |
|
fprintf(stderr, "%02x", (hash[i])&0xff); |
|
fprintf(stderr, "\n"); |
|
#endif |
|
if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1) |
|
fatal("key_verify failed for server_host_key"); |
|
key_free(server_host_key); |
|
xfree(signature); |
|
|
|
kex_derive_keys(kex, hash, shared_secret); |
|
BN_clear_free(shared_secret); |
|
packet_set_kex(kex); |
|
|
|
/* save session id */ |
|
session_id2_len = 20; |
|
session_id2 = xmalloc(session_id2_len); |
|
memcpy(session_id2, hash, session_id2_len); |
|
} |
|
|
|
/* |
|
* Authenticate user |
* Authenticate user |
*/ |
*/ |
|
|
|
|
|
|
struct Authctxt { |
struct Authctxt { |
const char *server_user; |
const char *server_user; |
|
const char *local_user; |
const char *host; |
const char *host; |
const char *service; |
const char *service; |
AuthenticationConnection *agent; |
|
Authmethod *method; |
Authmethod *method; |
int success; |
int success; |
char *authlist; |
char *authlist; |
|
/* pubkey */ |
Key *last_key; |
Key *last_key; |
sign_cb_fn *last_key_sign; |
sign_cb_fn *last_key_sign; |
int last_key_hint; |
int last_key_hint; |
|
AuthenticationConnection *agent; |
|
/* hostbased */ |
|
Key **keys; |
|
int nkeys; |
}; |
}; |
struct Authmethod { |
struct Authmethod { |
char *name; /* string to compare against server's list */ |
char *name; /* string to compare against server's list */ |
|
|
int userauth_pubkey(Authctxt *authctxt); |
int userauth_pubkey(Authctxt *authctxt); |
int userauth_passwd(Authctxt *authctxt); |
int userauth_passwd(Authctxt *authctxt); |
int userauth_kbdint(Authctxt *authctxt); |
int userauth_kbdint(Authctxt *authctxt); |
|
int userauth_hostbased(Authctxt *authctxt); |
|
|
void userauth(Authctxt *authctxt, char *authlist); |
void userauth(Authctxt *authctxt, char *authlist); |
|
|
|
|
userauth_kbdint, |
userauth_kbdint, |
&options.kbd_interactive_authentication, |
&options.kbd_interactive_authentication, |
&options.batch_mode}, |
&options.batch_mode}, |
|
{"hostbased", |
|
userauth_hostbased, |
|
&options.hostbased_authentication, |
|
NULL}, |
{"none", |
{"none", |
userauth_none, |
userauth_none, |
NULL, |
NULL, |
|
|
}; |
}; |
|
|
void |
void |
ssh_userauth2(const char *server_user, char *host) |
ssh_userauth2(const char *local_user, const char *server_user, char *host, |
|
Key **keys, int nkeys) |
{ |
{ |
Authctxt authctxt; |
Authctxt authctxt; |
int type; |
int type; |
|
|
/* setup authentication context */ |
/* setup authentication context */ |
authctxt.agent = ssh_get_authentication_connection(); |
authctxt.agent = ssh_get_authentication_connection(); |
authctxt.server_user = server_user; |
authctxt.server_user = server_user; |
|
authctxt.local_user = local_user; |
authctxt.host = host; |
authctxt.host = host; |
authctxt.service = "ssh-connection"; /* service name */ |
authctxt.service = "ssh-connection"; /* service name */ |
authctxt.success = 0; |
authctxt.success = 0; |
authctxt.method = authmethod_lookup("none"); |
authctxt.method = authmethod_lookup("none"); |
authctxt.authlist = NULL; |
authctxt.authlist = NULL; |
|
authctxt.keys = keys; |
|
authctxt.nkeys = nkeys; |
if (authctxt.method == NULL) |
if (authctxt.method == NULL) |
fatal("ssh_userauth2: internal error: cannot send userauth none request"); |
fatal("ssh_userauth2: internal error: cannot send userauth none request"); |
|
|
|
|
Authctxt *authctxt = ctxt; |
Authctxt *authctxt = ctxt; |
Key *key = NULL; |
Key *key = NULL; |
Buffer b; |
Buffer b; |
int alen, blen, pktype, sent = 0; |
int alen, blen, sent = 0; |
char *pkalg, *pkblob, *fp; |
char *pkalg, *pkblob, *fp; |
|
|
if (authctxt == NULL) |
if (authctxt == NULL) |
|
|
debug("no last key or no sign cb"); |
debug("no last key or no sign cb"); |
break; |
break; |
} |
} |
if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) { |
if (key_type_from_name(pkalg) == KEY_UNSPEC) { |
debug("unknown pkalg %s", pkalg); |
debug("unknown pkalg %s", pkalg); |
break; |
break; |
} |
} |
|
|
{ |
{ |
Key *private; |
Key *private; |
char prompt[300], *passphrase; |
char prompt[300], *passphrase; |
int success = 0, quit, i; |
int quit, i; |
struct stat st; |
struct stat st; |
|
|
if (stat(filename, &st) < 0) { |
if (stat(filename, &st) < 0) { |
debug3("no such identity: %s", filename); |
debug3("no such identity: %s", filename); |
return NULL; |
return NULL; |
} |
} |
private = key_new(KEY_UNSPEC); |
private = key_load_private_type(KEY_UNSPEC, filename, "", NULL); |
if (!load_private_key(filename, "", private, NULL)) { |
if (private == NULL) { |
if (options.batch_mode) { |
if (options.batch_mode) |
key_free(private); |
|
return NULL; |
return NULL; |
} |
|
snprintf(prompt, sizeof prompt, |
snprintf(prompt, sizeof prompt, |
"Enter passphrase for key '%.100s': ", filename); |
"Enter passphrase for key '%.100s': ", filename); |
for (i = 0; i < options.number_of_password_prompts; i++) { |
for (i = 0; i < options.number_of_password_prompts; i++) { |
passphrase = read_passphrase(prompt, 0); |
passphrase = read_passphrase(prompt, 0); |
if (strcmp(passphrase, "") != 0) { |
if (strcmp(passphrase, "") != 0) { |
success = load_private_key(filename, |
private = key_load_private_type(KEY_UNSPEC, filename, |
passphrase, private, NULL); |
passphrase, NULL); |
quit = 0; |
quit = 0; |
} else { |
} else { |
debug2("no passphrase given, try next key"); |
debug2("no passphrase given, try next key"); |
|
|
} |
} |
memset(passphrase, 0, strlen(passphrase)); |
memset(passphrase, 0, strlen(passphrase)); |
xfree(passphrase); |
xfree(passphrase); |
if (success || quit) |
if (private != NULL || quit) |
break; |
break; |
debug2("bad passphrase given, try again..."); |
debug2("bad passphrase given, try again..."); |
} |
} |
if (!success) { |
|
key_free(private); |
|
return NULL; |
|
} |
|
} |
} |
return private; |
return private; |
} |
} |
|
|
int key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp, |
int key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp, |
u_char *data, int datalen) |
u_char *data, int datalen) |
{ |
{ |
return key_sign(key, sigp, lenp, data, datalen); |
return key_sign(key, sigp, lenp, data, datalen); |
} |
} |
|
|
int |
int |
|
|
packet_send(); |
packet_send(); |
} |
} |
|
|
|
/* |
|
* this will be move to an external program (ssh-keysign) ASAP. ssh-keysign |
|
* will be setuid-root and the sbit can be removed from /usr/bin/ssh. |
|
*/ |
|
int |
|
userauth_hostbased(Authctxt *authctxt) |
|
{ |
|
Key *private = NULL; |
|
Buffer b; |
|
u_char *signature, *blob; |
|
char *chost, *pkalg, *p; |
|
const char *service; |
|
u_int blen, slen; |
|
int ok, i, len, found = 0; |
|
|
|
p = get_local_name(packet_get_connection_in()); |
|
if (p == NULL) { |
|
error("userauth_hostbased: cannot get local ipaddr/name"); |
|
return 0; |
|
} |
|
len = strlen(p) + 2; |
|
chost = xmalloc(len); |
|
strlcpy(chost, p, len); |
|
strlcat(chost, ".", len); |
|
debug2("userauth_hostbased: chost %s", chost); |
|
/* check for a useful key */ |
|
for (i = 0; i < authctxt->nkeys; i++) { |
|
private = authctxt->keys[i]; |
|
if (private && private->type != KEY_RSA1) { |
|
found = 1; |
|
/* we take and free the key */ |
|
authctxt->keys[i] = NULL; |
|
break; |
|
} |
|
} |
|
if (!found) { |
|
xfree(chost); |
|
return 0; |
|
} |
|
if (key_to_blob(private, &blob, &blen) == 0) { |
|
key_free(private); |
|
xfree(chost); |
|
return 0; |
|
} |
|
service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : |
|
authctxt->service; |
|
pkalg = xstrdup(key_ssh_name(private)); |
|
buffer_init(&b); |
|
/* construct data */ |
|
buffer_put_string(&b, session_id2, session_id2_len); |
|
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); |
|
buffer_put_cstring(&b, authctxt->server_user); |
|
buffer_put_cstring(&b, service); |
|
buffer_put_cstring(&b, authctxt->method->name); |
|
buffer_put_cstring(&b, pkalg); |
|
buffer_put_string(&b, blob, blen); |
|
buffer_put_cstring(&b, chost); |
|
buffer_put_cstring(&b, authctxt->local_user); |
|
#ifdef DEBUG_PK |
|
buffer_dump(&b); |
|
#endif |
|
debug2("xxx: chost %s", chost); |
|
ok = key_sign(private, &signature, &slen, buffer_ptr(&b), buffer_len(&b)); |
|
key_free(private); |
|
buffer_free(&b); |
|
if (ok != 0) { |
|
error("key_sign failed"); |
|
xfree(chost); |
|
xfree(pkalg); |
|
return 0; |
|
} |
|
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_cstring(pkalg); |
|
packet_put_string(blob, blen); |
|
packet_put_cstring(chost); |
|
packet_put_cstring(authctxt->local_user); |
|
packet_put_string(signature, slen); |
|
memset(signature, 's', slen); |
|
xfree(signature); |
|
xfree(chost); |
|
xfree(pkalg); |
|
|
|
packet_send(); |
|
return 1; |
|
} |
|
|
/* find auth method */ |
/* find auth method */ |
|
|
/* |
/* |
|
|
/* |
/* |
* Given the authentication method list sent by the server, return the |
* Given the authentication method list sent by the server, return the |
* next method we should try. If the server initially sends a nil list, |
* next method we should try. If the server initially sends a nil list, |
* use a built-in default list. |
* use a built-in default list. |
*/ |
*/ |
Authmethod * |
Authmethod * |
authmethod_get(char *authlist) |
authmethod_get(char *authlist) |