From 46f96ed5e3127394a0cd4dcb961404b792f743b4 Mon Sep 17 00:00:00 2001 From: Jakub Slawinski Date: Thu, 10 Jul 2014 10:24:59 +0200 Subject: Initial project structure based on Active Port Forwarder 0.8.4. --- src/client_initialization.c | 343 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 343 insertions(+) create mode 100644 src/client_initialization.c (limited to 'src/client_initialization.c') diff --git a/src/client_initialization.c b/src/client_initialization.c new file mode 100644 index 0000000..efde9a9 --- /dev/null +++ b/src/client_initialization.c @@ -0,0 +1,343 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003-2007 jeremian + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include +#include + +#include "client_initialization.h" +#include "first_run.h" +#include "network.h" +#include "base64.h" +#include "ssl_routines.h" +#include "client_configuration_struct.h" +#include "client_signals.h" + +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; +} + +int +initialize_client_stage2(ClientRealm* cr, unsigned char* buff, char wanttoexit) +{ + SslFd_send_message(ClientRealm_get_realmType(cr) | TYPE_SSL | TYPE_ZLIB, + ClientRealm_get_masterSslFd(cr), buff, 5); + buff[0] = 0; + SslFd_get_message(ClientRealm_get_realmType(cr) | TYPE_SSL | TYPE_ZLIB, + ClientRealm_get_masterSslFd(cr), buff, -5); + + if ( buff[0] == 0 ) { + aflog(LOG_T_INIT, LOG_I_CRIT, + "Connection with afserver failed"); + if (wanttoexit) { + exit(1); + } + else { + close(SslFd_get_fd(ClientRealm_get_masterSslFd(cr))); + return 1; + } + } + if ( buff[0] == AF_S_WRONG ) { + aflog(LOG_T_INIT, LOG_I_ERR, + "Wrong password"); + if (wanttoexit) { + exit(1); + } + else { + close(SslFd_get_fd(ClientRealm_get_masterSslFd(cr))); + return 1; + } + } + if ( buff[0] == AF_S_CANT_OPEN ) { + aflog(LOG_T_INIT, LOG_I_ERR, + "Server is full"); + if (wanttoexit) { + exit(1); + } + else { + close(SslFd_get_fd(ClientRealm_get_masterSslFd(cr))); + return 1; + } + } + if ( buff[0] != AF_S_LOGIN ) { + aflog(LOG_T_INIT, LOG_I_ERR, + "Incompatible server type or server full"); + if (wanttoexit) { + exit(1); + } + else { + close(SslFd_get_fd(ClientRealm_get_masterSslFd(cr))); + return 1; + } + } + + ClientRealm_set_realmType(cr, buff[3]); + ClientRealm_set_usersLimit(cr, buff[1] * 256 + buff[2]); + return 0; +} + +int +initialize_client_stage3(ClientRealm* cr, int* buflength, fd_set* allset, fd_set* wset, int* maxfdp1, + char wanttoexit) +{ + int i; + socklen_t len; + ConnectUser** usersTable; + usersTable = calloc(ClientRealm_get_usersLimit(cr), sizeof(ConnectUser*)); + if (usersTable == NULL) { + aflog(LOG_T_INIT, LOG_I_CRIT, + "Calloc error - unable to successfully communicate with server"); + if (wanttoexit) { + exit(1); + } + else { + close(SslFd_get_fd(ClientRealm_get_masterSslFd(cr))); + return 1; + } + } + ClientRealm_set_usersTable(cr, usersTable); + for (i = 0; i < ClientRealm_get_usersLimit(cr); ++i) { + usersTable[i] = ConnectUser_new(); + if (usersTable[i] == NULL) { + aflog(LOG_T_INIT, LOG_I_CRIT, + "Calloc error - unable to successfully communicate with server"); + if (wanttoexit) { + exit(1); + } + else { + close(SslFd_get_fd(ClientRealm_get_masterSslFd(cr))); + return 1; + } + } + } + + len = 4; + if (getsockopt(SslFd_get_fd(ClientRealm_get_masterSslFd(cr)), SOL_SOCKET, SO_SNDBUF, buflength, &len) == -1) { + aflog(LOG_T_INIT, LOG_I_CRIT, + "Can't get socket send buffer size - exiting..."); + if (wanttoexit) { + exit(1); + } + else { + close(SslFd_get_fd(ClientRealm_get_masterSslFd(cr))); + return 2; + } + } + + FD_ZERO(allset); + FD_ZERO(wset); + + FD_SET(SslFd_get_fd(ClientRealm_get_masterSslFd(cr)), allset); + (*maxfdp1) = SslFd_get_fd(ClientRealm_get_masterSslFd(cr)) + 1; + return 0; +} -- cgit v1.1