bool clSSH::AuthenticateServer(wxString& message) { int state; unsigned char* hash = NULL; char* hexa = NULL; message.Clear(); state = ssh_is_server_known(m_session); #if LIBSSH_VERSION_INT < SSH_VERSION_INT(0, 6, 1) int hlen = 0; hlen = ssh_get_pubkey_hash(m_session, &hash); if(hlen < 0) { throw clException("Unable to obtain server public key!"); } #else size_t hlen = 0; ssh_key key = NULL; ssh_get_publickey(m_session, &key); ssh_get_publickey_hash(key, SSH_PUBLICKEY_HASH_SHA1, &hash, &hlen); if(hlen == 0) { throw clException("Unable to obtain server public key!"); } #endif switch(state) { case SSH_SERVER_KNOWN_OK: free(hash); return true; case SSH_SERVER_KNOWN_CHANGED: hexa = ssh_get_hexa(hash, hlen); message << _("Host key for server changed: it is now:\n") << hexa << "\n" << _("Accept server authentication?"); free(hexa); free(hash); return false; case SSH_SERVER_FOUND_OTHER: message << _("The host key for this server was not found but another type of key exists.\n") << _("An attacker might change the default server key to confuse your client into thinking the key " "does not exist\n") << _("Accept server authentication?"); free(hash); return false; case SSH_SERVER_FILE_NOT_FOUND: message << _("Could not find known host file.\n") << _("If you accept the host key here, the file will be automatically created.\n"); /* fallback to SSH_SERVER_NOT_KNOWN behavior */ case SSH_SERVER_NOT_KNOWN: hexa = ssh_get_hexa(hash, hlen); message << _("The server is unknown. Do you trust the host key?\n") << _("Public key hash: ") << hexa << "\n" << _("Accept server authentication?"); free(hexa); free(hash); return false; default: case SSH_SERVER_ERROR: throw clException(wxString() << "An error occurred: " << ssh_get_error(m_session)); } return false; }
int verify_knownhost(ssh_session session){ char *hexa; int state; char buf[10]; unsigned char *hash = NULL; int hlen; state=ssh_is_server_known(session); hlen = ssh_get_pubkey_hash(session, &hash); if (hlen < 0) { return -1; } switch(state){ case SSH_SERVER_KNOWN_OK: break; /* ok */ case SSH_SERVER_KNOWN_CHANGED: fprintf(stderr,"Host key for server changed : server's one is now :\n"); ssh_print_hexa("Public key hash",hash, hlen); free(hash); fprintf(stderr,"For security reason, connection will be stopped\n"); return -1; case SSH_SERVER_FOUND_OTHER: fprintf(stderr,"The host key for this server was not found but an other type of key exists.\n"); fprintf(stderr,"An attacker might change the default server key to confuse your client" "into thinking the key does not exist\n" "We advise you to rerun the client with -d or -r for more safety.\n"); return -1; case SSH_SERVER_FILE_NOT_FOUND: fprintf(stderr,"Could not find known host file. If you accept the host key here,\n"); fprintf(stderr,"the file will be automatically created.\n"); /* fallback to SSH_SERVER_NOT_KNOWN behavior */ case SSH_SERVER_NOT_KNOWN: hexa = ssh_get_hexa(hash, hlen); fprintf(stderr,"The server is unknown. Do you trust the host key ?\n"); fprintf(stderr, "Public key hash: %s\n", hexa); free(hexa); fgets(buf,sizeof(buf),stdin); if(strncasecmp(buf,"yes",3)!=0){ return -1; } fprintf(stderr,"This new key will be written on disk for further usage. do you agree ?\n"); fgets(buf,sizeof(buf),stdin); if(strncasecmp(buf,"yes",3)==0){ if (ssh_write_knownhost(session) < 0) { free(hash); fprintf(stderr, "error %s\n", strerror(errno)); return -1; } } break; case SSH_SERVER_ERROR: free(hash); fprintf(stderr,"%s",ssh_get_error(session)); return -1; } free(hash); return 0; }
/** * Check if the host doesn't change * @return bool true if it's ok, false else */ bool Kssh::check_known_host() { QString error, server_public_key; int state, hlen; unsigned char *hash = NULL; // get the public key of the server state = ssh_is_server_known(this->m_session); hlen = ssh_get_pubkey_hash(this->m_session, &hash); if (hlen < 0) { #ifdef DEBUG Klog::debug("no public key for this server"); #endif return false; } server_public_key = QString(ssh_get_hexa(hash, hlen)); delete[] hash; switch (state) { case SSH_SERVER_KNOWN_OK: break; case SSH_SERVER_KNOWN_CHANGED: Klog::warning(QString("Host key for server changed, now it's : ") + server_public_key); return false; case SSH_SERVER_FOUND_OTHER: error = "The host key for this server was not found but an other type of key exists.\n" "into thinking the key does not exist.\n"; Klog::warning(error); return false; case SSH_SERVER_FILE_NOT_FOUND: Klog::warning("Could not find known host file. This file will be automatically created."); if (ssh_write_knownhost(this->m_session) < 0) { #ifdef DEBUG Klog::debug("impossible to write the knowhosts"); #endif } break; case SSH_SERVER_NOT_KNOWN: Klog::warning("The server is unknown. This new key will be written on disk for further usage."); if (ssh_write_knownhost(this->m_session) < 0) { #ifdef DEBUG Klog::debug("impossible to write the knowhosts"); #endif } break; case SSH_SERVER_ERROR: Klog::error(QString("Error while check the knowhosts : ") + QString(ssh_get_error(this->m_session))); return false; } return true; }
/** * @brief Print a buffer as colon separated hex string. * * @param descr Description printed in front of the hex string. * * @param what What should be converted to a hex string. * * @param len Length of the buffer to convert. */ void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len) { char *hexa = ssh_get_hexa(what, len); if (hexa == NULL) { return; } printf("%s: %s\n", descr, hexa); free(hexa); }
int verify_knownhost(ssh_session session) { int state, hlen; unsigned char *hash = NULL; char *hexa; char buf[10]; state = ssh_is_server_known(session); hlen = ssh_get_pubkey_hash(session, &hash); if (hlen < 0) return -1; switch (state) { case SSH_SERVER_KNOWN_OK: break; /* ok */ case SSH_SERVER_KNOWN_CHANGED: fprintf(stderr, "Host key for server changed: it is now:\n"); ssh_print_hexa("Public key hash", hash, hlen); fprintf(stderr, "For security reasons, connection will be stopped\n"); free(hash); return -1; case SSH_SERVER_FOUND_OTHER: fprintf(stderr, "The host key for this server was not found but an other" "type of key exists.\n"); fprintf(stderr, "An attacker might change the default server key to" "confuse your client into thinking the key does not exist\n"); free(hash); return -1; case SSH_SERVER_FILE_NOT_FOUND: fprintf(stderr, "Could not find known host file.\n"); fprintf(stderr, "If you accept the host key here, the file will be" "automatically created.\n"); /* fallback to SSH_SERVER_NOT_KNOWN behavior */ case SSH_SERVER_NOT_KNOWN: hexa = ssh_get_hexa(hash, hlen); fprintf(stderr,"The server is unknown. Do you trust the host key [yes/no]?\n"); fprintf(stderr, "Public key hash: %s\n", hexa); free(hexa); if (fgets(buf, sizeof(buf), stdin) == NULL) { free(hash); return -1; } if (strncasecmp(buf, "yes", 3) != 0) { free(hash); return -1; } if (ssh_write_knownhost(session) < 0) { fprintf(stderr, "Error %s\n", strerror(errno)); free(hash); return -1; } break; case SSH_SERVER_ERROR: fprintf(stderr, "Error %s", ssh_get_error(session)); free(hash); return -1; } free(hash); return 0; }
static const gchar * verify_knownhost (CockpitSshData *data) { const gchar *ret = "unknown-hostkey"; ssh_key key = NULL; unsigned char *hash = NULL; const char *type = NULL; int state; gsize len; data->host_key = get_knownhosts_line (data->session); if (data->host_key == NULL) { ret = "internal-error"; goto done; } if (ssh_get_publickey (data->session, &key) != SSH_OK) { g_warning ("Couldn't look up ssh host key"); ret = "internal-error"; goto done; } type = ssh_key_type_to_char (ssh_key_type (key)); if (type == NULL) { g_warning ("Couldn't lookup host key type"); ret = "internal-error"; goto done; } if (ssh_get_publickey_hash (key, SSH_PUBLICKEY_HASH_MD5, &hash, &len) < 0) { g_warning ("Couldn't hash ssh public key"); ret = "internal-error"; goto done; } else { data->host_fingerprint = ssh_get_hexa (hash, len); ssh_clean_pubkey_hash (&hash); } if (data->expect_key) { /* Only check that the host key matches this specifically */ if (g_str_equal (data->host_key, data->expect_key)) { g_debug ("%s: host key matched expected", data->logname); ret = NULL; /* success */ } else { /* A empty expect_key is used by the frontend to force failure. Don't warn about it. */ if (data->expect_key[0]) g_message ("%s: host key did not match expected", data->logname); } } else { if (ssh_options_set (data->session, SSH_OPTIONS_KNOWNHOSTS, data->knownhosts_file) != SSH_OK) { g_warning ("Couldn't set knownhosts file location"); ret = "internal-error"; goto done; } state = ssh_is_server_known (data->session); if (state == SSH_SERVER_KNOWN_OK) { g_debug ("%s: verified host key", data->logname); ret = NULL; /* success */ goto done; } else if (state == SSH_SERVER_ERROR) { if (g_atomic_int_get (data->connecting)) g_warning ("%s: couldn't check host key: %s", data->logname, ssh_get_error (data->session)); ret = "internal-error"; goto done; } switch (state) { case SSH_SERVER_KNOWN_OK: case SSH_SERVER_ERROR: g_assert_not_reached (); break; case SSH_SERVER_KNOWN_CHANGED: g_message ("%s: %s host key for server has changed to: %s", data->logname, type, data->host_fingerprint); break; case SSH_SERVER_FOUND_OTHER: g_message ("%s: host key for this server changed key type: %s", data->logname, type); break; case SSH_SERVER_FILE_NOT_FOUND: g_debug ("Couldn't find the known hosts file"); /* fall through */ case SSH_SERVER_NOT_KNOWN: g_message ("%s: %s host key for server is not known: %s", data->logname, type, data->host_fingerprint); break; } } done: if (key) ssh_key_free (key); return ret; }
gint remmina_ssh_auth_gui (RemminaSSH *ssh, RemminaInitDialog *dialog, gboolean threaded) { gchar *tips; gchar *keyname; gint ret; size_t len; guchar *pubkey; ssh_key server_pubkey; /* Check if the server's public key is known */ ret = ssh_is_server_known (ssh->session); switch (ret) { case SSH_SERVER_KNOWN_OK: break; case SSH_SERVER_NOT_KNOWN: case SSH_SERVER_FILE_NOT_FOUND: case SSH_SERVER_KNOWN_CHANGED: case SSH_SERVER_FOUND_OTHER: if ( ssh_get_publickey(ssh->session, &server_pubkey) != SSH_OK ) { remmina_ssh_set_error(ssh, "ssh_get_publickey() has failed: %s"); return 0; } if ( ssh_get_publickey_hash(server_pubkey, SSH_PUBLICKEY_HASH_MD5, &pubkey, &len) != 0 ) { ssh_key_free(server_pubkey); remmina_ssh_set_error(ssh, "ssh_get_publickey_hash() has failed: %s"); return 0; } ssh_key_free(server_pubkey); keyname = ssh_get_hexa (pubkey, len); if (threaded) gdk_threads_enter(); if (ret == SSH_SERVER_NOT_KNOWN || ret == SSH_SERVER_FILE_NOT_FOUND) { ret = remmina_init_dialog_serverkey_unknown (dialog, keyname); } else { ret = remmina_init_dialog_serverkey_changed (dialog, keyname); } if (threaded) { gdk_flush();gdk_threads_leave();} ssh_string_free_char(keyname); ssh_clean_pubkey_hash (&pubkey); if (ret != GTK_RESPONSE_OK) return -1; ssh_write_knownhost (ssh->session); break; case SSH_SERVER_ERROR: default: remmina_ssh_set_error (ssh, "SSH known host checking failed: %s"); return 0; } /* Try empty password or existing password first */ ret = remmina_ssh_auth (ssh, NULL); if (ret > 0) return 1; /* Requested for a non-empty password */ if (ret < 0) { if (!dialog) return -1; switch (ssh->auth) { case SSH_AUTH_PASSWORD: tips = _("Authenticating %s's password to SSH server %s..."); keyname = _("SSH password"); break; case SSH_AUTH_PUBLICKEY: tips = _("Authenticating %s's identity to SSH server %s..."); keyname = _("SSH private key passphrase"); break; default: return FALSE; } if (ssh->auth != SSH_AUTH_AUTO_PUBLICKEY) { if (threaded) gdk_threads_enter(); remmina_init_dialog_set_status (dialog, tips, ssh->user, ssh->server); ret = remmina_init_dialog_authpwd (dialog, keyname, FALSE); if (threaded) { gdk_flush();gdk_threads_leave();} if (ret != GTK_RESPONSE_OK) return -1; } ret = remmina_ssh_auth (ssh, dialog->password); } if (ret <= 0) { return 0; } return 1; }
/** Verifying the target host. @param session is the created ssh session @return the server status */ int SSHSession::verifyKnownHost(ssh_session session) { unsigned char *hash = NULL; auto state = ssh_is_server_known(session); auto hlen = ssh_get_pubkey_hash(session, &hash); char buf[10]; char *hexa; if (hlen < 0) return -1; switch (state) { case SSH_SERVER_KNOWN_OK: return 1; // ok case SSH_SERVER_KNOWN_CHANGED: std::cout << "Host key for server changed: it is now" << std::endl; ssh_print_hexa("Public key hash", hash, hlen); delete hash; return -1; case SSH_SERVER_FOUND_OTHER: std::cout << "The host key for this server was not found but an other type of key exists." << std::endl; delete hash; return -1; case SSH_SERVER_FILE_NOT_FOUND: std::cout << "Could not find known host file." << std::endl; std::cout << "If you accept the host key here, the file will be automatically created." << std::endl; delete hash; return -1; case SSH_SERVER_NOT_KNOWN: hexa = ssh_get_hexa(hash, hlen); std::cout << "The server is unknown. Do you trust the host key?" << std::endl; std::cout << "Public key hash: " << hexa << std::endl; delete hexa; if (fgets(buf, sizeof(buf), stdin) == NULL) { delete hash; return -1; } if (strncasecmp(buf, "yes", 3) != 0) { delete hash; return -1; } if (ssh_write_knownhost(session) < 0) { std::cout << "Error" << std::endl; delete hash; return -1; } break; case SSH_SERVER_ERROR: std::cout << "Error" << ssh_get_error(session) << std::endl; delete hash; return -1; } delete hash; return 0; }
static int _sftp_connect(const char *uri) { char *scheme = NULL; char *user = NULL; char *passwd = NULL; char *host = NULL; unsigned int port = 0; char *path = NULL; unsigned char *hash = NULL; int hlen; int rc = -1; int state = SSH_SERVER_ERROR; int timeout = 10; int method; char *verbosity; if (_connected) { return 0; } rc = c_parse_uri(uri, &scheme, &user, &passwd, &host, &port, &path); if (rc < 0) { goto out; } DEBUG_SFTP(("csync_sftp - conntecting to: %s\n", host)); /* create the session */ _ssh_session = ssh_new(); if (_ssh_session == NULL) { fprintf(stderr, "csync_sftp - error creating new connection: %s\n", strerror(errno)); rc = -1; goto out; } rc = ssh_options_set(_ssh_session, SSH_OPTIONS_TIMEOUT, &timeout); if (rc < 0) { fprintf(stderr, "csync_sftp - error setting options: %s\n", strerror(errno)); goto out; } rc = ssh_options_set(_ssh_session, SSH_OPTIONS_COMPRESSION_C_S, "none"); if (rc < 0) { fprintf(stderr, "csync_sftp - error setting options: %s\n", strerror(errno)); goto out; } rc = ssh_options_set(_ssh_session, SSH_OPTIONS_COMPRESSION_S_C, "none"); if (rc < 0) { fprintf(stderr, "csync_sftp - error setting options: %s\n", strerror(errno)); goto out; } ssh_options_set(_ssh_session, SSH_OPTIONS_HOST, host); if (rc < 0) { fprintf(stderr, "csync_sftp - error setting options: %s\n", strerror(errno)); goto out; } if (port) { ssh_options_set(_ssh_session, SSH_OPTIONS_PORT, &port); if (rc < 0) { fprintf(stderr, "csync_sftp - error setting options: %s\n", strerror(errno)); goto out; } DEBUG_SFTP(("csync_sftp - port set to: %d\n", port)); } if (user && *user) { ssh_options_set(_ssh_session, SSH_OPTIONS_USER, user); if (rc < 0) { fprintf(stderr, "csync_sftp - error setting options: %s\n", strerror(errno)); goto out; } DEBUG_SFTP(("csync_sftp - username set to: %s\n", user)); } verbosity = getenv("CSYNC_SFTP_LOG_VERBOSITY"); if (verbosity) { rc = ssh_options_set(_ssh_session, SSH_OPTIONS_LOG_VERBOSITY_STR, verbosity); if (rc < 0) { goto out; } } /* read ~/.ssh/config */ rc = ssh_options_parse_config(_ssh_session, NULL); if (rc < 0) { goto out; } _ssh_callbacks = (ssh_callbacks) c_malloc(sizeof(struct ssh_callbacks_struct)); if (_ssh_callbacks == NULL) { rc = -1; goto out; } ZERO_STRUCTP(_ssh_callbacks); _ssh_callbacks->userdata = _userdata; _ssh_callbacks->auth_function = _ssh_auth_callback; ssh_callbacks_init(_ssh_callbacks); ssh_set_callbacks(_ssh_session, _ssh_callbacks); rc = ssh_connect(_ssh_session); if (rc < 0) { fprintf(stderr, "csync_sftp - error connecting to the server: %s\n", ssh_get_error(_ssh_session)); ssh_disconnect(_ssh_session); _ssh_session = NULL; ssh_finalize(); goto out; } hlen = ssh_get_pubkey_hash(_ssh_session, &hash); if (hlen < 0) { fprintf(stderr, "csync_sftp - error connecting to the server: %s\n", ssh_get_error(_ssh_session)); ssh_disconnect(_ssh_session); _ssh_session = NULL; ssh_finalize(); goto out; } /* check the server public key hash */ state = ssh_is_server_known(_ssh_session); switch (state) { case SSH_SERVER_KNOWN_OK: break; case SSH_SERVER_KNOWN_CHANGED: fprintf(stderr, "csync_sftp - The host key for this server was " "not found, but another type of key exists.\n" "An attacker might change the default server key to confuse your " "client into thinking the key does not exist.\n" "Please contact your system administrator.\n" "%s\n", ssh_get_error(_ssh_session)); ssh_print_hexa("csync_sftp - public key hash", hash, hlen); ssh_disconnect(_ssh_session); _ssh_session = NULL; ssh_finalize(); rc = -1; goto out; break; case SSH_SERVER_FOUND_OTHER: fprintf(stderr, "csync_sftp - the host key for this server was not " "found but an other type of key exists.\n"); fprintf(stderr, "csync_sftp - an attacker might change the default " "server key to confuse your client into thinking the key does not " "exist\n"); fprintf(stderr, "The host key for the server %s has changed.\n" "This could either mean that DNS SPOOFING is happening or the IP " "address for the host and its host key have changed at the same time.\n" "The fingerprint for the key sent by the remote host is:\n", host); ssh_print_hexa("", hash, hlen); fprintf(stderr, "Please contact your system administrator.\n" "%s\n", ssh_get_error(_ssh_session)); ssh_disconnect(_ssh_session); _ssh_session = NULL; ssh_finalize(); rc = -1; goto out; break; case SSH_SERVER_NOT_KNOWN: if (_authcb) { char *hexa; char *prompt; char buf[4] = {0}; hexa = ssh_get_hexa(hash, hlen); if (hexa == NULL) { ssh_disconnect(_ssh_session); _ssh_session = NULL; ssh_finalize(); rc = -1; goto out; } if (asprintf(&prompt, "The authenticity of host '%s' can't be established.\n" "RSA key fingerprint is %s.\n" "Are you sure you want to continue connecting (yes/no)?", host, hexa) < 0 ) { free(hexa); ssh_disconnect(_ssh_session); _ssh_session = NULL; ssh_finalize(); rc = -1; goto out; } free(hexa); if ((*_authcb)(prompt, buf, sizeof(buf), 1, 0, _userdata) < 0) { free(prompt); ssh_disconnect(_ssh_session); _ssh_session = NULL; ssh_finalize(); rc = -1; goto out; } free(prompt); if (strncasecmp(buf, "yes", 3) != 0) { ssh_disconnect(_ssh_session); _ssh_session = NULL; ssh_finalize(); rc = -1; goto out; } if (ssh_write_knownhost(_ssh_session) < 0) { ssh_disconnect(_ssh_session); _ssh_session = NULL; ssh_finalize(); rc = -1; goto out; } } else { fprintf(stderr,"csync_sftp - the server is unknown. Connect manually to " "the host to retrieve the public key hash, then try again.\n"); } ssh_disconnect(_ssh_session); _ssh_session = NULL; ssh_finalize(); rc = -1; goto out; break; case SSH_SERVER_ERROR: fprintf(stderr, "%s\n", ssh_get_error(_ssh_session)); ssh_disconnect(_ssh_session); _ssh_session = NULL; ssh_finalize(); rc = -1; goto out; break; default: break; } /* Try to authenticate */ rc = ssh_userauth_none(_ssh_session, NULL); if (rc == SSH_AUTH_ERROR) { ssh_disconnect(_ssh_session); _ssh_session = NULL; ssh_finalize(); rc = -1; goto out; } #if 0 /* authenticate with the server */ if (passwd && *passwd) { DEBUG_SFTP(("csync_sftp - authenticating with user/password\n")); /* * This is tunneled cleartext password authentication and possibly needs * to be allowed by the ssh server. Set 'PasswordAuthentication yes' */ auth = ssh_userauth_password(_ssh_session, user, passwd); } else { DEBUG_SFTP(("csync_sftp - authenticating with pubkey\n")); auth = ssh_userauth_autopubkey(_ssh_session, NULL); } if (auth == SSH_AUTH_ERROR) { fprintf(stderr, "csync_sftp - authenticating with pubkey: %s\n", ssh_get_error(_ssh_session)); ssh_disconnect(_ssh_session); _ssh_session = NULL; ssh_finalize(); rc = -1; goto out; } if (auth != SSH_AUTH_SUCCESS) { if (_authcb != NULL) { auth = auth_kbdint(_ssh_session); if (auth == SSH_AUTH_ERROR) { fprintf(stderr,"csync_sftp - authentication failed: %s\n", ssh_get_error(_ssh_session)); ssh_disconnect(_ssh_session); _ssh_session = NULL; ssh_finalize(); rc = -1; goto out; } } else { ssh_disconnect(_ssh_session); _ssh_session = NULL; ssh_finalize(); rc = -1; goto out; } } #endif method = ssh_auth_list(_ssh_session); while (rc != SSH_AUTH_SUCCESS) { /* Try to authenticate with public key first */ if (method & SSH_AUTH_METHOD_PUBLICKEY) { rc = ssh_userauth_autopubkey(_ssh_session, NULL); if (rc == SSH_AUTH_ERROR) { ssh_disconnect(_ssh_session); _ssh_session = NULL; ssh_finalize(); rc = -1; goto out; } else if (rc == SSH_AUTH_SUCCESS) { break; } } /* Try to authenticate with keyboard interactive */ if (method & SSH_AUTH_METHOD_INTERACTIVE) { rc = auth_kbdint(_ssh_session, user, passwd); if (rc == SSH_AUTH_ERROR) { ssh_disconnect(_ssh_session); _ssh_session = NULL; ssh_finalize(); rc = -1; goto out; } else if (rc == SSH_AUTH_SUCCESS) { break; } } /* Try to authenticate with password */ if ((method & SSH_AUTH_METHOD_PASSWORD) && passwd && *passwd) { rc = ssh_userauth_password(_ssh_session, user, passwd); if (rc == SSH_AUTH_ERROR) { ssh_disconnect(_ssh_session); _ssh_session = NULL; ssh_finalize(); rc = -1; goto out; } else if (rc == SSH_AUTH_SUCCESS) { break; } } } DEBUG_SFTP(("csync_sftp - creating sftp channel...\n")); /* start the sftp session */ _sftp_session = sftp_new(_ssh_session); if (_sftp_session == NULL) { fprintf(stderr, "csync_sftp - sftp error initialising channel: %s\n", ssh_get_error(_ssh_session)); rc = -1; goto out; } rc = sftp_init(_sftp_session); if (rc < 0) { fprintf(stderr, "csync_sftp - error initialising sftp: %s\n", ssh_get_error(_ssh_session)); goto out; } DEBUG_SFTP(("csync_sftp - connection established...\n")); _connected = 1; rc = 0; out: SAFE_FREE(scheme); SAFE_FREE(user); SAFE_FREE(passwd); SAFE_FREE(host); SAFE_FREE(path); SAFE_FREE(hash); return rc; }
int ssh_connect_p (char *haddr, int hport, char *remote_version, char * remote_fingerprint) { struct timeval tv; double elapsed_time; ssh_session my_ssh_session; int version; int myversion; int hlen; int rc; int state; int i; unsigned char *hash = NULL; char * fingerprint; int in_known_host; int sshv1,sshv2,sshv3; gettimeofday(&tv, NULL); my_ssh_session = ssh_new(); if (my_ssh_session == NULL) return STATE_CRITICAL; ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, haddr); ssh_options_set(my_ssh_session, SSH_OPTIONS_PORT, &hport); rc = ssh_connect(my_ssh_session); if (rc != SSH_OK) { printf ("Connect to Server failed\n"); exit (STATE_CRITICAL); } in_known_host=-1; state = ssh_is_server_known(my_ssh_session); hlen = ssh_get_pubkey_hash(my_ssh_session, &hash); /* Get the finger print as a string */ fingerprint = ssh_get_hexa(hash, hlen); if(remote_fingerprint && strcmp(remote_fingerprint, "known_host") == NULL) { if(state != SSH_SERVER_KNOWN_OK) { printf ("SSH CRITICAL - Fingerprint (%s) checked in known_hosts failed\n", remote_fingerprint,fingerprint); exit(STATE_CRITICAL); } else { in_known_host=1; } } /* FIXME: This alwats eval to false... */ if(remote_fingerprint && strcmp(remote_fingerprint, "known_host") && strcmp(remote_fingerprint, fingerprint)) { printf ("SSH CRITICAL - Fingerprint (%s) mismatched %s\n", remote_fingerprint,fingerprint); free(fingerprint); exit(STATE_CRITICAL); } version = ssh_get_openssh_version(my_ssh_session); if(remote_version && sscanf(remote_version, "%d.%d.%d", &sshv1, &sshv2, &sshv3)) { myversion = SSH_VERSION_INT(sshv1, sshv2, sshv3); if(version < myversion) { printf ("SSH WARNING version on server is below %s\n", remote_version); exit(STATE_CRITICAL); } } elapsed_time = (double)deltime(tv) / 1.0e6; printf (_("SSH OK - fingerprint: %s (Version %d) known_host_check:%d | %s\n"), fingerprint, version,in_known_host, fperfdata("time", elapsed_time, "s", FALSE, 0, FALSE, 0, TRUE, 0, TRUE, (int)socket_timeout)); free(fingerprint); ssh_disconnect(my_ssh_session); ssh_free(my_ssh_session); exit(STATE_OK); }
bool SSHClient::sshConnect(int /* fd */, std::string &hostname) { // GNASH_REPORT_FUNCTION; char *password; char *banner; char *hexa; // We always need a hostname to connect to if (ssh_options_set(_session, SSH_OPTIONS_HOST, hostname.c_str()) < 0) { log_error(_("Couldn't set hostname option")); return false; } // We always need a user name for the connection if (_user.empty()) { if (ssh_options_set(_session, SSH_OPTIONS_USER, _user.c_str()) < 0) { log_error(_("Couldn't set user name option")); return false; } } // Start a new session _session = ssh_new(); if(ssh_connect(_session)){ log_error(_("Connection failed : %s\n"), ssh_get_error(_session)); sshShutdown(); return false; } _state = ssh_is_server_known(_session); unsigned char *hash = 0; int hlen = ssh_get_pubkey_hash(_session, &hash); if (hlen < 0) { sshShutdown(); return false; } switch(_state){ case SSH_SERVER_KNOWN_OK: // ok log_debug(_("SSH Server is currently known: %d"), _state); break; case SSH_SERVER_KNOWN_CHANGED: log_error(_("Host key for server changed : server's one is now: ")); ssh_print_hexa(_("Public key hash"), hash, hlen); free(hash); log_error(_("For security reason, connection will be stopped")); sshShutdown(); return false;; case SSH_SERVER_FOUND_OTHER: log_error(_("The host key for this server was not found but an other type of key exists.")); log_error(_("An attacker might change the default server key to confuse your client" " into thinking the key does not exist" "We advise you to rerun the client with -d or -r for more safety.")); sshShutdown(); return false;; case SSH_SERVER_NOT_KNOWN: hexa = ssh_get_hexa(hash, hlen); free(hash); // FIXME: for now, accecpt all new keys, and update the // $HOME/.ssh/know_hosts file. #if 0 log_error(_("The server is unknown. Do you trust the host key ? (yes,no)")); log_error(_("Public key hash: %s"), hexa); free(hexa); fgets(buf, sizeof(buf), stdin); if(strncasecmp(buf, "yes", 3) != 0){ sshShutdown(); return false; } log_error(_("This new key will be written on disk for further usage. do you agree? (yes,no) ")); fgets(buf, sizeof(buf), stdin); if(strncasecmp(buf, "yes", 3)==0){ if(ssh_write_knownhost(_session)) log_error(ssh_get_error(_session)); } #else if(ssh_write_knownhost(_session)) { log_error(ssh_get_error(_session)); } #endif break; case SSH_SERVER_ERROR: free(hash); log_error(ssh_get_error(_session)); sshShutdown(); return false; } free(hash); ssh_userauth_none(_session, NULL); int auth = ssh_auth_list(_session); // log_debug("auth: 0x%04x", auth); log_debug(_("supported auth methods: ")); if (auth & SSH_AUTH_METHOD_PUBLICKEY) { log_debug(_("\tpublickey")); } if (auth & SSH_AUTH_METHOD_INTERACTIVE) { log_debug(_("\tkeyboard-interactive")); } /* no ? you should :) */ auth=ssh_userauth_autopubkey(_session, NULL); if(auth == SSH_AUTH_ERROR){ log_debug(_("Authenticating with pubkey: %s"), ssh_get_error(_session)); ssh_finalize(); return false; } banner = ssh_get_issue_banner(_session); if(banner){ log_debug(banner); free(banner); } if(auth != SSH_AUTH_SUCCESS){ auth = authKbdint(_session); if(auth == SSH_AUTH_ERROR){ log_error(_("authenticating with keyb-interactive: %s"), ssh_get_error(_session)); ssh_finalize(); return false; } } if(auth != SSH_AUTH_SUCCESS){ password = getpass("Password: "******"Authentication failed: %s"), ssh_get_error(_session)); ssh_disconnect(_session); ssh_finalize(); return false; } memset(password, 0, strlen(password)); } ssh_log(_session, SSH_LOG_FUNCTIONS, "Authentication success"); #if 0 if(strstr(argv[0],"sftp")){ sftp = 1; ssh_log(_session, SSH_LOG_FUNCTIONS, "Doing sftp instead"); } if(!sftp){ if(!cmds[0]) shell(_session); else batch_shell(_session); } else do_sftp(_session); if(!sftp && !cmds[0]) do_cleanup(0); #endif return true; }
/** @brief returns the OIDs of the mechs that have usable credentials */ static int ssh_gssapi_match(ssh_session session, gss_OID_set *valid_oids) { OM_uint32 maj_stat, min_stat, lifetime; gss_OID_set actual_mechs; gss_buffer_desc namebuf; gss_name_t client_id = GSS_C_NO_NAME; gss_OID oid; unsigned int i; char *ptr; int ret; if (session->gssapi->client.client_deleg_creds == NULL) { if (session->opts.gss_client_identity != NULL) { namebuf.value = (void *)session->opts.gss_client_identity; namebuf.length = strlen(session->opts.gss_client_identity); maj_stat = gss_import_name(&min_stat, &namebuf, GSS_C_NT_USER_NAME, &client_id); if (GSS_ERROR(maj_stat)) { ret = SSH_ERROR; goto end; } } maj_stat = gss_acquire_cred(&min_stat, client_id, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, GSS_C_INITIATE, &session->gssapi->client.creds, &actual_mechs, NULL); if (GSS_ERROR(maj_stat)) { ret = SSH_ERROR; goto end; } } else { session->gssapi->client.creds = session->gssapi->client.client_deleg_creds; maj_stat = gss_inquire_cred(&min_stat, session->gssapi->client.creds, &client_id, NULL, NULL, &actual_mechs); if (GSS_ERROR(maj_stat)) { ret = SSH_ERROR; goto end; } } gss_create_empty_oid_set(&min_stat, valid_oids); /* double check each single cred */ for (i = 0; i < actual_mechs->count; i++) { /* check lifetime is not 0 or skip */ lifetime = 0; oid = &actual_mechs->elements[i]; maj_stat = gss_inquire_cred_by_mech(&min_stat, session->gssapi->client.creds, oid, NULL, &lifetime, NULL, NULL); if (maj_stat == GSS_S_COMPLETE && lifetime > 0) { gss_add_oid_set_member(&min_stat, oid, valid_oids); ptr = ssh_get_hexa(oid->elements, oid->length); SSH_LOG(SSH_LOG_DEBUG, "GSSAPI valid oid %d : %s\n", i, ptr); SAFE_FREE(ptr); } } ret = SSH_OK; end: gss_release_name(&min_stat, &client_id); return ret; }
/** @internal * @brief handles an user authentication using GSSAPI */ int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n_oid, ssh_string *oids){ char service_name[]="host"; gss_buffer_desc name_buf; gss_name_t server_name; /* local server fqdn */ OM_uint32 maj_stat, min_stat; unsigned int i; char *ptr; gss_OID_set supported; /* oids supported by server */ gss_OID_set both_supported; /* oids supported by both client and server */ gss_OID_set selected; /* oid selected for authentication */ int present=0; int oid_count=0; struct gss_OID_desc_struct oid; int rc; if (ssh_callbacks_exists(session->server_callbacks, gssapi_select_oid_function)){ ssh_string oid_s = session->server_callbacks->gssapi_select_oid_function(session, user, n_oid, oids, session->server_callbacks->userdata); if (oid_s != NULL){ if (ssh_gssapi_init(session) == SSH_ERROR) return SSH_ERROR; session->gssapi->state = SSH_GSSAPI_STATE_RCV_TOKEN; rc = ssh_gssapi_send_response(session, oid_s); ssh_string_free(oid_s); return rc; } else { return ssh_auth_reply_default(session,0); } } gss_create_empty_oid_set(&min_stat, &both_supported); maj_stat = gss_indicate_mechs(&min_stat, &supported); for (i=0; i < supported->count; ++i){ ptr = ssh_get_hexa(supported->elements[i].elements, supported->elements[i].length); SSH_LOG(SSH_LOG_DEBUG, "Supported mech %d: %s\n", i, ptr); free(ptr); } for (i=0 ; i< n_oid ; ++i){ unsigned char *oid_s = (unsigned char *) ssh_string_data(oids[i]); size_t len = ssh_string_len(oids[i]); if(len < 2 || oid_s[0] != SSH_OID_TAG || ((size_t)oid_s[1]) != len - 2){ SSH_LOG(SSH_LOG_WARNING,"GSSAPI: received invalid OID"); continue; } oid.elements = &oid_s[2]; oid.length = len - 2; gss_test_oid_set_member(&min_stat,&oid,supported,&present); if(present){ gss_add_oid_set_member(&min_stat,&oid,&both_supported); oid_count++; } } gss_release_oid_set(&min_stat, &supported); if (oid_count == 0){ SSH_LOG(SSH_LOG_PROTOCOL,"GSSAPI: no OID match"); ssh_auth_reply_default(session, 0); gss_release_oid_set(&min_stat, &both_supported); return SSH_OK; } /* from now we have room for context */ if (ssh_gssapi_init(session) == SSH_ERROR) return SSH_ERROR; name_buf.value = service_name; name_buf.length = strlen(name_buf.value) + 1; maj_stat = gss_import_name(&min_stat, &name_buf, (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &server_name); if (maj_stat != GSS_S_COMPLETE) { SSH_LOG(SSH_LOG_WARNING, "importing name %d, %d", maj_stat, min_stat); ssh_gssapi_log_error(SSH_LOG_WARNING, "importing name", maj_stat); return -1; } maj_stat = gss_acquire_cred(&min_stat, server_name, 0, both_supported, GSS_C_ACCEPT, &session->gssapi->server_creds, &selected, NULL); gss_release_name(&min_stat, &server_name); gss_release_oid_set(&min_stat, &both_supported); if (maj_stat != GSS_S_COMPLETE) { SSH_LOG(SSH_LOG_WARNING, "error acquiring credentials %d, %d", maj_stat, min_stat); ssh_gssapi_log_error(SSH_LOG_WARNING, "acquiring creds", maj_stat); ssh_auth_reply_default(session,0); return SSH_ERROR; } SSH_LOG(SSH_LOG_PROTOCOL, "acquiring credentials %d, %d", maj_stat, min_stat); /* finding which OID from client we selected */ for (i=0 ; i< n_oid ; ++i){ unsigned char *oid_s = (unsigned char *) ssh_string_data(oids[i]); size_t len = ssh_string_len(oids[i]); if(len < 2 || oid_s[0] != SSH_OID_TAG || ((size_t)oid_s[1]) != len - 2){ SSH_LOG(SSH_LOG_WARNING,"GSSAPI: received invalid OID"); continue; } oid.elements = &oid_s[2]; oid.length = len - 2; gss_test_oid_set_member(&min_stat,&oid,selected,&present); if(present){ SSH_LOG(SSH_LOG_PACKET, "Selected oid %d", i); break; } } session->gssapi->mech.length = oid.length; session->gssapi->mech.elements = malloc(oid.length); if (session->gssapi->mech.elements == NULL){ ssh_set_error_oom(session); return SSH_ERROR; } memcpy(session->gssapi->mech.elements, oid.elements, oid.length); gss_release_oid_set(&min_stat, &selected); session->gssapi->user = strdup(user); session->gssapi->service = service_name; session->gssapi->state = SSH_GSSAPI_STATE_RCV_TOKEN; return ssh_gssapi_send_response(session, oids[i]); }
// Verify if Server is a known host. int SSH_Socket::verify_knownhost() { int state; size_t hlen; unsigned char *hash = nullptr; char *hexa; state = ssh_is_server_known(session); ssh_key srv_pubkey; int rc; rc = ssh_get_publickey(session, &srv_pubkey); if(rc < 0) { return -1; } rc = ssh_get_publickey_hash(srv_pubkey, SSH_PUBLICKEY_HASH_SHA1, &hash, &hlen); ssh_key_free(srv_pubkey); if(rc < 0) { return -1; } switch(state) { case SSH_SERVER_KNOWN_OK: break; /* ok */ case SSH_SERVER_KNOWN_CHANGED: std::cout << "Host key for server changed: it is now" << std::endl; ssh_print_hexa("Public key hash", hash, hlen); std::cout << "For security reasons, connection will be stopped" << std::endl; free(hash); return -1; case SSH_SERVER_FOUND_OTHER: std::cout << "The host key for this server was not found but an other" << "type of key exists." << std::endl; std::cout << "An attacker might change the default server key to" << "confuse your client into thinking the key does not exist" << std::endl; free(hash); return -1; case SSH_SERVER_FILE_NOT_FOUND: std::cout << "Could not find known host file." << std::endl; std::cout << "If you accept the host key here, the file will be" << "automatically created." << std::endl; /* fallback to SSH_SERVER_NOT_KNOWN behavior */ case SSH_SERVER_NOT_KNOWN: hexa = ssh_get_hexa(hash, hlen); //Do you trust the host key?\n"); std::cout << "The server is unknown. Adding Key." << std::endl; std::cout << "Public key hash: " << hexa << std::endl; free(hexa); /* if (fgets(buf, sizeof(buf), stdin) == NULL) { free(hash); return -1; } if (strncasecmp(buf, "yes", 3) != 0) { free(hash); return -1; } */ if(ssh_write_knownhost(session) < 0) { std::cout << "Error: " << strerror(errno) << std::endl; free(hash); return -1; } break; case SSH_SERVER_ERROR: std::cout << "Error: " << ssh_get_error(session) << std::endl; free(hash); return -1; } free(hash); return 0; }
/** @brief returns the OIDs of the mechs that work with both * hostname and username */ static int ssh_gssapi_match(ssh_session session, char *hostname, char *username, gss_OID_set *valid_oids, int deleg){ gss_buffer_desc host_namebuf, user_namebuf; gss_name_t host_name, user_name; OM_uint32 maj_stat, min_stat; gss_OID_set supported; gss_OID oid; gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; gss_cred_id_t client_creds = GSS_C_NO_CREDENTIAL; unsigned int i; char *ptr; char hostname_buf[256]; gss_create_empty_oid_set(&min_stat, valid_oids); maj_stat = gss_indicate_mechs(&min_stat, &supported); for (i=0; i < supported->count; ++i){ ptr=ssh_get_hexa(supported->elements[i].elements, supported->elements[i].length); SSH_LOG(SSH_LOG_DEBUG, "GSSAPI oid supported %d : %s\n",i, ptr); SAFE_FREE(ptr); } user_namebuf.value = username; user_namebuf.length = strlen(username) + 1; maj_stat = gss_import_name(&min_stat, &user_namebuf, (gss_OID) GSS_C_NT_USER_NAME, &user_name); if (maj_stat != GSS_S_COMPLETE) { SSH_LOG(SSH_LOG_DEBUG, "importing name %d, %d", maj_stat, min_stat); ssh_gssapi_log_error(SSH_LOG_DEBUG, "importing name", maj_stat); return -1; } snprintf(hostname_buf, sizeof(hostname_buf),"host@%s", hostname); host_namebuf.value = hostname_buf; host_namebuf.length = strlen(hostname_buf) + 1; maj_stat = gss_import_name(&min_stat, &host_namebuf, (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &host_name); if (maj_stat != GSS_S_COMPLETE) { SSH_LOG(0, "importing name %d, %d", maj_stat, min_stat); ssh_gssapi_log_error(0, "importing name", maj_stat); return -1; } ssh_gssapi_init(session); session->gssapi->client_name = user_name; session->gssapi->client.server_name = host_name; session->gssapi->user = strdup(username); for (i=0; i<supported->count; ++i){ oid = &supported->elements[i]; maj_stat = gss_init_sec_context(&min_stat, session->gssapi->client.client_deleg_creds, &ctx, host_name, oid, GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | (deleg ? GSS_C_DELEG_FLAG : 0), 0, NULL, &input_token, NULL, &output_token, NULL, NULL); if (!GSS_ERROR(maj_stat)){ gss_OID_set tmp; if (session->gssapi->client.client_deleg_creds != GSS_C_NO_CREDENTIAL){ /* we know the oid is ok since init_sec_context worked */ gss_add_oid_set_member(&min_stat, oid, valid_oids); SSH_LOG(SSH_LOG_PROTOCOL, "Matched oid %u for server (with forwarding)", i); } else { gss_create_empty_oid_set(&min_stat, &tmp); gss_add_oid_set_member(&min_stat, oid, &tmp); maj_stat = gss_acquire_cred(&min_stat, user_name, 0, tmp, GSS_C_INITIATE, &client_creds, NULL, NULL); gss_release_oid_set(&min_stat, &tmp); if (!GSS_ERROR(maj_stat)){ gss_release_cred(&min_stat, &client_creds); gss_add_oid_set_member(&min_stat,oid,valid_oids); SSH_LOG(SSH_LOG_PROTOCOL, "Matched oid %u for server", i); } } } gss_delete_sec_context(&min_stat,&ctx, &output_token); ctx = GSS_C_NO_CONTEXT; } return SSH_OK; }