📄 sshconnect2.c
字号:
/* * Copyright (c) 2000 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "includes.h"RCSID("$OpenBSD: sshconnect2.c,v 1.138 2004/06/13 12:53:24 djm Exp $");#include "openbsd-compat/sys-queue.h"#include "ssh.h"#include "ssh2.h"#include "xmalloc.h"#include "buffer.h"#include "packet.h"#include "compat.h"#include "bufaux.h"#include "cipher.h"#include "kex.h"#include "myproposal.h"#include "sshconnect.h"#include "authfile.h"#include "dh.h"#include "authfd.h"#include "log.h"#include "readconf.h"#include "misc.h"#include "match.h"#include "dispatch.h"#include "canohost.h"#include "msg.h"#include "pathnames.h"#ifdef GSSAPI#include "ssh-gss.h"#endif/* import */extern char *client_version_string;extern char *server_version_string;extern Options options;/* * SSH2 key exchange */u_char *session_id2 = NULL;u_int session_id2_len = 0;char *xxx_host;struct sockaddr *xxx_hostaddr;Kex *xxx_kex = NULL;static intverify_host_key_callback(Key *hostkey){ if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1) fatal("Host key verification failed."); return 0;}voidssh_kex2(char *host, struct sockaddr *hostaddr){ Kex *kex; xxx_host = host; xxx_hostaddr = hostaddr; if (options.ciphers == (char *)-1) { logit("No valid ciphers for protocol version 2 given, using defaults."); options.ciphers = NULL; } if (options.ciphers != NULL) { myproposal[PROPOSAL_ENC_ALGS_CTOS] = 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) { myproposal[PROPOSAL_COMP_ALGS_CTOS] = myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib,none"; } else { myproposal[PROPOSAL_COMP_ALGS_CTOS] = myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib"; } if (options.macs != NULL) { myproposal[PROPOSAL_MAC_ALGS_CTOS] = myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; } if (options.hostkeyalgorithms != NULL) myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = options.hostkeyalgorithms; if (options.rekey_limit) packet_set_rekey_limit(options.rekey_limit); /* start key exchange */ kex = kex_setup(myproposal); kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; kex->client_version_string=client_version_string; kex->server_version_string=server_version_string; kex->verify_host_key=&verify_host_key_callback; xxx_kex = kex; dispatch_run(DISPATCH_BLOCK, &kex->done, kex); session_id2 = kex->session_id; session_id2_len = kex->session_id_len;#ifdef DEBUG_KEXDH /* send 1st encrypted/maced/compressed message */ packet_start(SSH2_MSG_IGNORE); packet_put_cstring("markus"); packet_send(); packet_write_wait();#endif}/* * Authenticate user */typedef struct Authctxt Authctxt;typedef struct Authmethod Authmethod;typedef struct identity Identity;typedef struct idlist Idlist;struct identity { TAILQ_ENTRY(identity) next; AuthenticationConnection *ac; /* set if agent supports key */ Key *key; /* public/private key */ char *filename; /* comment for agent-only keys */ int tried; int isprivate; /* key points to the private key */};TAILQ_HEAD(idlist, identity);struct Authctxt { const char *server_user; const char *local_user; const char *host; const char *service; Authmethod *method; int success; char *authlist; /* pubkey */ Idlist keys; AuthenticationConnection *agent; /* hostbased */ Sensitive *sensitive; /* kbd-interactive */ int info_req_seen; /* generic */ void *methoddata;};struct Authmethod { char *name; /* string to compare against server's list */ int (*userauth)(Authctxt *authctxt); int *enabled; /* flag in option struct that enables method */ int *batch_flag; /* flag in option struct that disables method */};void input_userauth_success(int, u_int32_t, void *);void input_userauth_failure(int, u_int32_t, void *);void input_userauth_banner(int, u_int32_t, void *);void input_userauth_error(int, u_int32_t, void *);void input_userauth_info_req(int, u_int32_t, void *);void input_userauth_pk_ok(int, u_int32_t, void *);void input_userauth_passwd_changereq(int, u_int32_t, void *);int userauth_none(Authctxt *);int userauth_pubkey(Authctxt *);int userauth_passwd(Authctxt *);int userauth_kbdint(Authctxt *);int userauth_hostbased(Authctxt *);int userauth_kerberos(Authctxt *);#ifdef GSSAPIint 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 *);#endifvoid userauth(Authctxt *, char *);static int sign_and_send_pubkey(Authctxt *, Identity *);static void pubkey_prepare(Authctxt *);static void pubkey_cleanup(Authctxt *);static Key *load_identity_file(char *);static Authmethod *authmethod_get(char *authlist);static Authmethod *authmethod_lookup(const char *name);static char *authmethods_get(void);Authmethod authmethods[] = {#ifdef GSSAPI {"gssapi-with-mic", userauth_gssapi, &options.gss_authentication, NULL},#endif {"hostbased", userauth_hostbased, &options.hostbased_authentication, NULL}, {"publickey", userauth_pubkey, &options.pubkey_authentication, NULL}, {"keyboard-interactive", userauth_kbdint, &options.kbd_interactive_authentication, &options.batch_mode}, {"password", userauth_passwd, &options.password_authentication, &options.batch_mode}, {"none", userauth_none, NULL, NULL}, {NULL, NULL, NULL, NULL}};voidssh_userauth2(const char *local_user, const char *server_user, char *host, Sensitive *sensitive){ Authctxt authctxt; int type; if (options.challenge_response_authentication) options.kbd_interactive_authentication = 1; packet_start(SSH2_MSG_SERVICE_REQUEST); packet_put_cstring("ssh-userauth"); packet_send(); debug("SSH2_MSG_SERVICE_REQUEST sent"); packet_write_wait(); type = packet_read(); if (type != SSH2_MSG_SERVICE_ACCEPT) fatal("Server denied authentication request: %d", type); if (packet_remaining() > 0) { char *reply = packet_get_string(NULL); debug2("service_accept: %s", reply); xfree(reply); } else { debug2("buggy server: service_accept w/o service"); } packet_check_eom(); debug("SSH2_MSG_SERVICE_ACCEPT received"); if (options.preferred_authentications == NULL) options.preferred_authentications = authmethods_get(); /* setup authentication context */ memset(&authctxt, 0, sizeof(authctxt)); pubkey_prepare(&authctxt); authctxt.server_user = server_user; authctxt.local_user = local_user; authctxt.host = host; authctxt.service = "ssh-connection"; /* service name */ authctxt.success = 0; authctxt.method = authmethod_lookup("none"); authctxt.authlist = NULL; authctxt.methoddata = NULL; authctxt.sensitive = sensitive; authctxt.info_req_seen = 0; if (authctxt.method == NULL) fatal("ssh_userauth2: internal error: cannot send userauth none request"); /* initial userauth request */ userauth_none(&authctxt); dispatch_init(&input_userauth_error); dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure); dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner); dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt); /* loop until success */ pubkey_cleanup(&authctxt); dispatch_range(SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL); debug("Authentication succeeded (%s).", authctxt.method->name);}voiduserauth(Authctxt *authctxt, char *authlist){ if (authctxt->methoddata) { xfree(authctxt->methoddata); authctxt->methoddata = NULL; } if (authlist == NULL) { authlist = authctxt->authlist; } else { if (authctxt->authlist) xfree(authctxt->authlist); authctxt->authlist = authlist; } for (;;) { Authmethod *method = authmethod_get(authlist); if (method == NULL) fatal("Permission denied (%s).", authlist); authctxt->method = method; /* reset the per method handler */ dispatch_range(SSH2_MSG_USERAUTH_PER_METHOD_MIN, SSH2_MSG_USERAUTH_PER_METHOD_MAX, NULL); /* and try new method */ if (method->userauth(authctxt) != 0) { debug2("we sent a %s packet, wait for reply", method->name); break; } else { debug2("we did not send a packet, disable method"); method->enabled = NULL; } }}voidinput_userauth_error(int type, u_int32_t seq, void *ctxt){ fatal("input_userauth_error: bad message during authentication: " "type %d", type);}voidinput_userauth_banner(int type, u_int32_t seq, void *ctxt){ char *msg, *lang; debug3("input_userauth_banner"); msg = packet_get_string(NULL); lang = packet_get_string(NULL); if (options.log_level > SYSLOG_LEVEL_QUIET) fprintf(stderr, "%s", msg); xfree(msg); xfree(lang);}voidinput_userauth_success(int type, u_int32_t seq, void *ctxt){ Authctxt *authctxt = ctxt; if (authctxt == NULL) fatal("input_userauth_success: no authentication context"); if (authctxt->authlist) { xfree(authctxt->authlist); authctxt->authlist = NULL; } if (authctxt->methoddata) { xfree(authctxt->methoddata); authctxt->methoddata = NULL; } authctxt->success = 1; /* break out */}voidinput_userauth_failure(int type, u_int32_t seq, void *ctxt){ Authctxt *authctxt = ctxt; char *authlist = NULL; int partial; if (authctxt == NULL) fatal("input_userauth_failure: no authentication context"); authlist = packet_get_string(NULL); partial = packet_get_char(); packet_check_eom(); if (partial != 0) logit("Authenticated with partial success."); debug("Authentications that can continue: %s", authlist); userauth(authctxt, authlist);}voidinput_userauth_pk_ok(int type, u_int32_t seq, void *ctxt){ Authctxt *authctxt = ctxt; Key *key = NULL; Identity *id = NULL; Buffer b; int pktype, sent = 0; u_int alen, blen; char *pkalg, *fp; u_char *pkblob; if (authctxt == NULL) fatal("input_userauth_pk_ok: no authentication context"); if (datafellows & SSH_BUG_PKOK) { /* this is similar to SSH_BUG_PKAUTH */ debug2("input_userauth_pk_ok: SSH_BUG_PKOK"); pkblob = packet_get_string(&blen); buffer_init(&b); buffer_append(&b, pkblob, blen); pkalg = buffer_get_string(&b, &alen); buffer_free(&b); } else { pkalg = packet_get_string(&alen); pkblob = packet_get_string(&blen); } packet_check_eom(); debug("Server accepts key: pkalg %s blen %u", pkalg, blen); if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) { debug("unknown pkalg %s", pkalg); goto done; } if ((key = key_from_blob(pkblob, blen)) == NULL) { debug("no key from blob. pkalg %s", pkalg); goto done; } if (key->type != pktype) { error("input_userauth_pk_ok: type mismatch " "for decoded key (received %d, expected %d)", key->type, pktype); goto done; } fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); debug2("input_userauth_pk_ok: fp %s", fp); xfree(fp); /* * search keys in the reverse order, because last candidate has been * moved to the end of the queue. this also avoids confusion by * duplicate keys */ TAILQ_FOREACH_REVERSE(id, &authctxt->keys, idlist, next) { if (key_equal(key, id->key)) { sent = sign_and_send_pubkey(authctxt, id); break; } }done: if (key != NULL) key_free(key); xfree(pkalg); xfree(pkblob); /* try another method if we did not send a packet */ if (sent == 0) userauth(authctxt, NULL);}#ifdef GSSAPIintuserauth_gssapi(Authctxt *authctxt){ Gssctxt *gssctxt = NULL; static gss_OID_set gss_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 (gss_supported == NULL) gss_indicate_mechs(&min, &gss_supported); /* Check to see if the mechanism is usable before we offer it */ while (mech < gss_supported->count && !ok) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -