/** * @brief Check if the server is known. * * Checks the user's known host file for a previous connection to the * current server. * * @param[in] session The SSH session to use. * * @returns SSH_SERVER_KNOWN_OK: The server is known and has not changed.\n * SSH_SERVER_KNOWN_CHANGED: The server key has changed. Either you * are under attack or the administrator * changed the key. You HAVE to warn the * user about a possible attack.\n * SSH_SERVER_FOUND_OTHER: The server gave use a key of a type while * we had an other type recorded. It is a * possible attack.\n * SSH_SERVER_NOT_KNOWN: The server is unknown. User should * confirm the MD5 is correct.\n * SSH_SERVER_FILE_NOT_FOUND: The known host file does not exist. The * host is thus unknown. File will be * created if host key is accepted.\n * SSH_SERVER_ERROR: Some error happened. * * @see ssh_get_pubkey_hash() * * @bug There is no current way to remove or modify an entry into the known * host table. */ int ssh_is_server_known(ssh_session session) { FILE *file = NULL; char **tokens; char *host; char *hostport; const char *type; int match; int ret = SSH_SERVER_NOT_KNOWN; enter_function(); if (session->knownhosts == NULL) { if (ssh_options_apply(session) < 0) { ssh_set_error(session, SSH_REQUEST_DENIED, "Can't find a known_hosts file"); leave_function(); return SSH_SERVER_FILE_NOT_FOUND; } } if (session->host == NULL) { ssh_set_error(session, SSH_FATAL, "Can't verify host in known hosts if the hostname isn't known"); leave_function(); return SSH_SERVER_ERROR; } if (session->current_crypto == NULL){ ssh_set_error(session, SSH_FATAL, "ssh_is_host_known called without cryptographic context"); leave_function(); return SSH_SERVER_ERROR; } host = ssh_lowercase(session->host); hostport = ssh_hostport(host,session->port); if (host == NULL || hostport == NULL) { ssh_set_error_oom(session); SAFE_FREE(host); SAFE_FREE(hostport); leave_function(); return SSH_SERVER_ERROR; } do { tokens = ssh_get_knownhost_line(session, &file, session->knownhosts, &type); /* End of file, return the current state */ if (tokens == NULL) { break; } match = match_hashed_host(session, host, tokens[0]); if (match == 0){ match = match_hostname(hostport, tokens[0], strlen(tokens[0])); } if (match == 0) { match = match_hostname(host, tokens[0], strlen(tokens[0])); } if (match == 0) { match = match_hashed_host(session, hostport, tokens[0]); } if (match) { /* We got a match. Now check the key type */ if (strcmp(session->current_crypto->server_pubkey_type, type) != 0) { /* Different type. We don't override the known_changed error which is * more important */ if (ret != SSH_SERVER_KNOWN_CHANGED) ret = SSH_SERVER_FOUND_OTHER; tokens_free(tokens); continue; } /* so we know the key type is good. We may get a good key or a bad key. */ match = check_public_key(session, tokens); tokens_free(tokens); if (match < 0) { ret = SSH_SERVER_ERROR; break; } else if (match == 1) { ret = SSH_SERVER_KNOWN_OK; break; } else if(match == 0) { /* We override the status with the wrong key state */ ret = SSH_SERVER_KNOWN_CHANGED; } } else { tokens_free(tokens); } } while (1); if ( (ret == SSH_SERVER_NOT_KNOWN) && (session->StrictHostKeyChecking == 0) ) { ssh_write_knownhost(session); ret = SSH_SERVER_KNOWN_OK; } SAFE_FREE(host); SAFE_FREE(hostport); if (file != NULL) { fclose(file); } /* Return the current state at end of file */ leave_function(); return ret; }
int parse_body (char *buffer, int length, struct body_msg *body) { char *tmp = buffer; char *end = buffer + length; int offset; int off; char *bodyline; char *address; uint16_t port = 0; size_t keylen; struct reg_body *tmp_body = NULL; struct id_body *tmp_body1 = NULL; struct add_body *tmp_body2 = NULL; struct key_body *tmp_body3 = NULL; /* strip the beginning space */ for (tmp; ((*tmp == '\n') || (*tmp == '\r')) && ((tmp - buffer) < length); tmp++); offset = tmp - buffer; do { switch (*tmp) { case 'U': case 'u': { if (!tmp_body) tmp_body = create_reg_body (); body->type = BODYREG; if (off = check ("USER", 4, tmp, end)) { if (LOG_PARSER) log_info ("Body USER found in %u\n", tmp - buffer); offset += off; /* find the end of this header */ offset += find_end (tmp + off, end); /* find the user address */ tmp = tmp + off; for (tmp; (*tmp == ' ') && ((tmp) < end); tmp++); /* copy it to structure */ tmp_body->user = (char *) strndup (tmp, buffer + offset - tmp - 1); tmp_body->user_len = buffer + offset - tmp - 1; if (LOG_PARSER) log_info ("The user is : %s\n", tmp_body->user); tmp = buffer + offset; break; } } case 'A': case 'a': { if (off = check ("ADDRESS", 7, tmp, end)) { if (!tmp_body) tmp_body = create_reg_body (); body->type = BODYREG; if (LOG_PARSER) log_info ("Body ADDRESS found in %u\n", tmp - buffer); offset += off; /* find the end of this header */ offset += find_end (tmp + off, end); /* find the IP address */ tmp = tmp + off; for (tmp; (*tmp == ' ') && ((tmp) < end); tmp++); /* copy it to structure */ tmp_body->ip = (char *) strndup (tmp, buffer + offset - tmp - 1); tmp_body->ip_len = buffer + offset - tmp - 1; if (LOG_PARSER) log_info ("The IP address is : %s\n", tmp_body->ip); tmp = buffer + offset; break; } else if (off = check ("ADDER", 5, tmp, end)) { char *data; MPI val = mpi_alloc (0); if (!tmp_body2) tmp_body2 = create_add_body (); body->type = BODYADD; if (LOG_PARSER) log_info ("Body Adder found in %u\n", tmp - buffer); offset += off; /* find the end of this line */ offset += find_end (tmp + off, end); /* find the adder */ tmp = tmp + off; for (tmp; (*tmp == ' ') && ((tmp) < end); tmp++); data = m_alloc_clear (buffer + offset - tmp); strncpy (data, tmp, buffer + offset - tmp - 1); if (mpi_fromstr (val, data)) { mpi_free (val); m_free (data); tmp = buffer + offset; break; } tmp_body2->adder[tmp_body2->num] = val; (tmp_body2->num)++; m_free (data); tmp = buffer + offset; break; } } case 'P': case 'p': { if (off = check ("PORT", 4, tmp, end)) { if (!tmp_body) tmp_body = create_reg_body (); body->type = BODYREG; if (LOG_PARSER) log_info ("Body PORT found in %u\n", tmp - buffer); offset += off; /* find the end of this header */ offset += find_end (tmp + off, end); /* find the user address */ tmp = tmp + off; for (tmp; (*tmp == ' ') && ((tmp) < end); tmp++); for (tmp; tmp < (buffer + offset - 1); tmp++) { if ((*tmp - 48) <= 9 && (*tmp - 48) >= 0) port = port * 10 + (*tmp - 48); else { log_error ("Error while changing port to number\n"); return 1; } } /* copy it to structure */ tmp_body->port = port; if (LOG_PARSER) log_info ("The PORT is : %u\n", port); tmp = buffer + offset; break; } } case '-': { if (!tmp_body) tmp_body = create_reg_body (); body->type = BODYREG; if (keylen = check_public_key (tmp, end)) { tmp_body->public_key = (char *) strndup (tmp, keylen); tmp_body->pk_len = keylen; if (LOG_PARSER) log_info ("We found begin pgp length : %u\n" "%s\n", keylen, strndup (tmp, keylen)); tmp += (keylen + 1); } } break; case 'I': case 'i': { uint32_t address; char c; if (!tmp_body1) tmp_body1 = create_id_body (); body->type = BODYID; if (off = check ("ID_LIST", 7, tmp, end)) { if (LOG_PARSER) log_info ("Body id list found in %u\n", tmp - buffer); offset += off; /* find the end of this header */ offset += find_end (tmp + off, end); /* find the id */ tmp = tmp + off; for (tmp; (*tmp == ' ') && ((tmp) < end); tmp++); if (sscanf (tmp, "%x%c", &address, &c) == 2) { tmp_body1->id[tmp_body1->num] = address; (tmp_body1->num)++; } tmp = buffer + offset; break; } } case 'K': case 'k': { int length; if (!tmp_body3) tmp_body3 = create_key_body (); body->type = BODYKEY; if (off = check ("KEY", 3, tmp, end)) { if (LOG_PARSER) log_info ("Body key found in %u\n", tmp - buffer); offset += off; /* find the end of this header */ offset += find_end (tmp + off, end); /* find the key */ tmp = tmp + off; for (tmp; (*tmp == ' ') && ((tmp) < end); tmp++); length = buffer + offset - tmp; tmp_body3->radmsg = m_alloc (length); strncpy (tmp_body3->radmsg, tmp, length - 1); tmp_body3->radmsg[length] = '\0'; tmp_body3->length = length - 1; tmp = buffer + offset; break; } } default: { log_error ("Other body type is found %c. Dont know what to do in %u\n", *tmp, tmp - buffer); return 1; } } } while (*tmp != '\n' && *tmp != '\r' && tmp < end); if (body->type == BODYREG) { /* check if any field is empty, we need a full one */ if (!tmp_body->user || !tmp_body->ip || (tmp_body->port == 0) || !tmp_body->public_key) { if (tmp_body->user) m_free (tmp_body->user); if (tmp_body->ip) m_free (tmp_body->ip); if (tmp_body->public_key) m_free (tmp_body->public_key); m_free (tmp_body); return 1; } else { body->msg.regbody = tmp_body; tmp_body = NULL; return 0; } } else if (body->type == BODYID) { body->msg.idbody = tmp_body1; tmp_body1 = NULL; return 0; } else if (body->type == BODYADD) { body->msg.addbody = tmp_body2; tmp_body2 = NULL; return 0; } else if (body->type == BODYKEY) { body->msg.keybody = tmp_body3; tmp_body2 = NULL; return 0; } return 1; }
int initialize_client_stage1(ClientRealm* cr, SSL_CTX* ctx, unsigned char* buff, char wanttoexit, char ignorePublicKeys) { int n, nlen, elen, len, tmp; unsigned int olen; X509* server_cert; const EVP_MD *md; EVP_PKEY* pkey; EVP_MD_CTX md_ctx; unsigned char *encoded = NULL; char b64_encoded[100]; unsigned char *key_buf = NULL; assert((ClientRealm_get_tunnelType(cr) == 0) || (ClientRealm_get_tunnelType(cr) == 1)); switch (ClientRealm_get_tunnelType(cr)) { case 0: { if (ip_connect(&tmp, ClientRealm_get_serverName(cr), ClientRealm_get_managePort(cr), ClientRealm_get_ipFamily(cr), ClientRealm_get_localName(cr), ClientRealm_get_localPort(cr))) { #ifdef AF_INET6 aflog(LOG_T_INIT, LOG_I_CRIT, "tcp_connect_%s error for %s, %s", (ClientRealm_get_ipFamily(cr) & 0x02) ? "ipv4":(ClientRealm_get_ipFamily(cr) & 0x04) ? "ipv6":"unspec", ClientRealm_get_serverName(cr), ClientRealm_get_managePort(cr)); #else aflog(LOG_T_INIT, LOG_I_CRIT, "tcp_connect error for %s, %s", ClientRealm_get_serverName(cr), ClientRealm_get_managePort(cr)); #endif if (wanttoexit) { exit(1); } else { return 1; } } SslFd_set_fd(ClientRealm_get_masterSslFd(cr), tmp); break; } #ifdef HAVE_LIBPTHREAD case 1: { if (initialize_http_proxy_client(&tmp, cr, ctx)) { #ifdef AF_INET6 aflog(LOG_T_INIT, LOG_I_CRIT, "http_proxy_connect_%s error for %s, %s (proxy: %s, %s)", (ClientRealm_get_ipFamily(cr) & 0x02) ? "ipv4":(ClientRealm_get_ipFamily(cr) & 0x04) ? "ipv6":"unspec", ClientRealm_get_serverName(cr), ClientRealm_get_managePort(cr), HttpProxyOptions_get_proxyname(ClientRealm_get_httpProxyOptions(cr)), HttpProxyOptions_get_proxyport(ClientRealm_get_httpProxyOptions(cr))); #else aflog(LOG_T_INIT, LOG_I_CRIT, "http_proxy_connect error for %s, %s (proxy: %s, %s)", ClientRealm_get_serverName(cr), ClientRealm_get_managePort(cr), HttpProxyOptions_get_proxyname(ClientRealm_get_httpProxyOptions(cr)), HttpProxyOptions_get_proxyport(ClientRealm_get_httpProxyOptions(cr))); #endif if (wanttoexit) { exit(1); } else { return 1; } } SslFd_set_fd(ClientRealm_get_masterSslFd(cr), tmp); break; } #endif default: { aflog(LOG_T_INIT, LOG_I_CRIT, "Unknown tunnel type"); if (wanttoexit) { exit(1); } else { return 1; } break; } } SslFd_set_ssl(ClientRealm_get_masterSslFd(cr), SSL_new(ctx)); if (SSL_set_fd(SslFd_get_ssl(ClientRealm_get_masterSslFd(cr)), SslFd_get_fd(ClientRealm_get_masterSslFd(cr))) != 1) { aflog(LOG_T_INIT, LOG_I_CRIT, "Problem with initializing ssl... exiting"); if (wanttoexit) { exit(1); } else { close(SslFd_get_fd(ClientRealm_get_masterSslFd(cr))); return 2; } } alarm(60); aflog(LOG_T_INIT, LOG_I_INFO, "Trying SSL_connect"); if ((n = SSL_connect(SslFd_get_ssl(ClientRealm_get_masterSslFd(cr)))) == 1) { if ((server_cert = SSL_get_peer_certificate(SslFd_get_ssl(ClientRealm_get_masterSslFd(cr)))) == NULL) { aflog(LOG_T_MAIN, LOG_I_CRIT, "Server did not present a certificate... exiting"); exit(1); } /* FIXME: change almost everything here */ pkey = X509_get_pubkey(server_cert); if (pkey == NULL) { aflog(LOG_T_MAIN, LOG_I_CRIT, "Server's public key is invalid... exiting"); exit(1); } nlen = BN_num_bytes(pkey->pkey.rsa->n); elen = BN_num_bytes(pkey->pkey.rsa->e); len = nlen + elen; key_buf = malloc(len); if (key_buf == NULL) { aflog(LOG_T_MAIN, LOG_I_CRIT, "Cannot allocate memory for server's public key checking... exiting"); exit(1); } BN_bn2bin(pkey->pkey.rsa->n, key_buf); BN_bn2bin(pkey->pkey.rsa->e, key_buf + nlen); md = EVP_md5(); EVP_DigestInit(&md_ctx, md); EVP_DigestUpdate(&md_ctx, key_buf, len); encoded = calloc(1, EVP_MAX_MD_SIZE+1); if (encoded == NULL) { aflog(LOG_T_MAIN, LOG_I_CRIT, "Cannot allocate memory for server's public key checking... exiting"); exit(1); } EVP_DigestFinal(&md_ctx, encoded, &olen); if (b64_ntop(encoded, olen, b64_encoded, 100) == -1) { aflog(LOG_T_MAIN, LOG_I_CRIT, "Problem with base64 encoding... exiting"); exit(1); } switch (check_public_key(get_store_filename(), ClientRealm_get_serverName(cr), b64_encoded)) { case SSL_PUBLIC_KEY_VALID: /* public key is ok - do nothing */ break; case SSL_PUBLIC_KEY_NOT_KNOWN: aflog(LOG_T_MAIN, LOG_I_WARNING, "WARNING: implicitly added new server's public key to the list of known hosts"); add_public_key(get_store_filename(), ClientRealm_get_serverName(cr), b64_encoded); break; default: if (ignorePublicKeys) { aflog(LOG_T_MAIN, LOG_I_WARNING, "WARNING: Invalid server's public key... ignoring"); } else { aflog(LOG_T_MAIN, LOG_I_CRIT, "Invalid server's public key... exiting"); aflog(LOG_T_MAIN, LOG_I_CRIT, "Please delete conflicting entry in %s or use '--ignorepkeys' option", get_store_filename()); exit(1); } } memset(key_buf, 0, len); free(key_buf); free(encoded); aflog(LOG_T_INIT, LOG_I_INFO, "SSL_connect successful"); } else { alarm(0); aflog(LOG_T_INIT, LOG_I_CRIT, "SSL_connect has failed (%d | %d)... exiting", n, SSL_get_error(SslFd_get_ssl(ClientRealm_get_masterSslFd(cr)), n)); if (wanttoexit) { exit(1); } else { close(SslFd_get_fd(ClientRealm_get_masterSslFd(cr))); return 3; } } alarm(0); buff[0] = AF_S_LOGIN; buff[1] = ClientRealm_get_password(cr)[0]; buff[2] = ClientRealm_get_password(cr)[1]; buff[3] = ClientRealm_get_password(cr)[2]; buff[4] = ClientRealm_get_password(cr)[3]; return 0; }