summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJakub Sławiński2005-07-03 23:15:19 +0200
committerJoshua Judson Rosen2014-07-17 21:14:59 +0200
commitf2e4a5f9b0919dc16ea83a8826e8d52b02178b38 (patch)
treed226d27a9b81d67fc4493b7b1856c0b040267d77 /src
parentv0.7 (diff)
downloadapf-f2e4a5f9b0919dc16ea83a8826e8d52b02178b38.tar.gz
v0.7.1
- Added: afserver certificate storing and checking - Modified: generating keys and certificate - Fixed: creating apf directory - Fixed: some bugs in proxy tunnel initialization
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am7
-rw-r--r--src/activefor.h2
-rw-r--r--src/afclient.c37
-rw-r--r--src/afclient.h1
-rw-r--r--src/afserver.c37
-rw-r--r--src/afserver.h1
-rw-r--r--src/base64.c250
-rw-r--r--src/base64.h41
-rw-r--r--src/client_initialization.c86
-rw-r--r--src/client_initialization.h2
-rw-r--r--src/daemon.c61
-rw-r--r--src/daemon.h39
-rw-r--r--src/first_run.c286
-rw-r--r--src/first_run.h6
-rw-r--r--src/http_proxy_server.c1
-rw-r--r--src/inet_ntop.c4
-rw-r--r--src/make_ssl_handshake.c2
-rw-r--r--src/server_get.c67
-rw-r--r--src/ssl_routines.c81
-rw-r--r--src/ssl_routines.h34
-rw-r--r--src/usage.c5
21 files changed, 968 insertions, 82 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 282b514..9910314 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,13 +1,12 @@
bin_PROGRAMS = afserver afclient
-afserver_LDFLAGS = ${LINKED_PTHREADLIB}
afserver_SOURCES = afserver.c network.c file.c stats.c buflist.c remoteadmin.c \
server_check.c server_set.c server_eval.c server_find.c server_remove.c \
make_ssl_handshake.c first_run.c inet_ntop.c realmnames.c clientnames.c usernames.c \
http_proxy_functions.c http_proxy_server.c server_get.c thread_management.c \
- server_signals.c usage.c logging.c audit.c
-afclient_LDFLAGS = ${USE_RDYNAMIC} ${LINKED_LDLIB} ${LINKED_PTHREADLIB}
+ server_signals.c usage.c logging.c audit.c daemon.c
+afclient_LDFLAGS = ${USE_RDYNAMIC} ${LINKED_LDLIB}
afclient_SOURCES = afclient.c network.c stats.c buflist.c modules.c remoteadmin.c \
make_ssl_handshake.c first_run.c inet_ntop.c realmnames.c clientnames.c usernames.c \
http_proxy_functions.c http_proxy_client.c thread_management.c \
client_reverse_udp.c server_check.c client_initialization.c client_shutdown.c \
- client_signals.c usage.c logging.c audit.c
+ client_signals.c usage.c logging.c audit.c daemon.c base64.c ssl_routines.c
diff --git a/src/activefor.h b/src/activefor.h
index 76564cb..d058a9c 100644
--- a/src/activefor.h
+++ b/src/activefor.h
@@ -46,7 +46,7 @@
#define S_STATE_OPEN 7
#define S_STATE_STOPPED 11
-#define AF_VER(info) info" v0.7"
+#define AF_VER(info) info" v0.7.1"
#define TYPE_TCP 1
#define TYPE_UDP 3
diff --git a/src/afclient.c b/src/afclient.c
index 72f1f9c..798ec55 100644
--- a/src/afclient.c
+++ b/src/afclient.c
@@ -32,8 +32,10 @@ static struct option long_options[] = {
{"portnum", 1, 0, 'p'},
{"verbose", 0, 0, 'v'},
{"keyfile", 1, 0, 'k'},
+ {"storefile", 1, 0, 's'},
{"log", 1, 0, 'o'},
{"pass", 1, 0, 301},
+ {"ignorepkeys", 0, 0, 302},
#ifdef AF_INET6
{"ipv4", 0, 0, '4'},
{"ipv6", 0, 0, '6'},
@@ -85,6 +87,7 @@ main(int argc, char **argv)
char* desnam = NULL;
char* despor = NULL;
char* keys = NULL;
+ char* store = NULL;
char* dateformat = NULL;
char* katimeout = NULL;
char* artries = NULL;
@@ -95,6 +98,7 @@ main(int argc, char **argv)
char reverse = 0;
char tunneltype = 0;
char type = 0;
+ char ignorepkeys = 0;
struct sigaction act;
#ifdef HAVE_LIBDL
moduleT module = {0, NULL, NULL, NULL, NULL}, secmodule = {0, NULL, NULL, NULL, NULL};
@@ -132,7 +136,7 @@ main(int argc, char **argv)
#endif
while ((n = getopt_long(argc, argv,
- GETOPT_LONG_LIBDL(GETOPT_LONG_LIBPTHREAD(GETOPT_LONG_AF_INET6("huUn:m:d:p:vk:o:i:D:rP:X:VK:A:T:")))
+ GETOPT_LONG_LIBDL(GETOPT_LONG_LIBPTHREAD(GETOPT_LONG_AF_INET6("huUn:m:d:p:vk:s:o:i:D:rP:X:VK:A:T:")))
, long_options, 0)) != -1) {
switch (n) {
case 'h': {
@@ -185,6 +189,10 @@ main(int argc, char **argv)
keys = optarg;
break;
}
+ case 's': {
+ store = optarg;
+ break;
+ }
case 'o': {
addlogtarget(optarg);
break;
@@ -197,6 +205,10 @@ main(int argc, char **argv)
}
break;
}
+ case 302: {
+ ignorepkeys = 1;
+ break;
+ }
#ifdef AF_INET6
case '4': {
if (ipfam != 0) {
@@ -290,6 +302,9 @@ main(int argc, char **argv)
if (keys == NULL) {
keys = "client.rsa";
}
+ if (store == NULL) {
+ store = "known_hosts";
+ }
if ((reverse == 0) && (remote == 0) && (desnam == NULL)) {
gethostname(hostname, 100);
desnam = hostname;
@@ -360,9 +375,17 @@ main(int argc, char **argv)
"Setting cipher list failed... exiting");
exit(1);
}
- if ((temp2 = create_apf_dir())) {
+ if ((temp2 = create_apf_dir(0))) {
aflog(LOG_T_INIT, LOG_I_WARNING,
"Warning: Creating ~/.apf directory failed (%d)", temp2);
+ if ((temp2 = create_apf_dir(1))) {
+ aflog(LOG_T_INIT, LOG_I_WARNING,
+ "Warning: Creating ./apf directory failed (%d)", temp2);
+ }
+ }
+ if ((temp2 = create_publickey_store(&store))) {
+ aflog(LOG_T_INIT, LOG_I_WARNING,
+ "Warning: Something bad happened when creating public key store... (%d)", temp2);
}
if ((temp2 = generate_rsa_key(&keys))) {
aflog(LOG_T_INIT, LOG_I_WARNING,
@@ -397,9 +420,11 @@ main(int argc, char **argv)
}
#ifdef HAVE_LIBPTHREAD
- initialize_client_stage1(tunneltype, &master, name, manage, proxyname, proxyport, ipfam, ctx, buff, pass, 1);
+ initialize_client_stage1(tunneltype, &master, name, manage, proxyname, proxyport,
+ ipfam, ctx, buff, pass, 1, ignorepkeys);
#else
- initialize_client_stage1(tunneltype, &master, name, manage, NULL, NULL, ipfam, ctx, buff, pass, 1);
+ initialize_client_stage1(tunneltype, &master, name, manage, NULL, NULL,
+ ipfam, ctx, buff, pass, 1, ignorepkeys);
#endif
if (remote) {
@@ -678,10 +703,10 @@ main(int argc, char **argv)
if (temp2 == 0) {
#ifdef HAVE_LIBPTHREAD
if (initialize_client_stage1(tunneltype, &master, name, manage, proxyname, proxyport,
- ipfam, ctx, buff, pass, 0)) {
+ ipfam, ctx, buff, pass, 0, ignorepkeys)) {
#else
if (initialize_client_stage1(tunneltype, &master, name, manage, NULL, NULL,
- ipfam, ctx, buff, pass, 0)) {
+ ipfam, ctx, buff, pass, 0, ignorepkeys)) {
#endif
temp2 = 1;
}
diff --git a/src/afclient.h b/src/afclient.h
index c2b52bb..156b408 100644
--- a/src/afclient.h
+++ b/src/afclient.h
@@ -36,6 +36,7 @@
#include "usage.h"
#include "logging.h"
#include "audit.h"
+#include "daemon.h"
#include <openssl/rsa.h>
#include <openssl/ssl.h>
diff --git a/src/afserver.c b/src/afserver.c
index 76f8ffc..2361ebe 100644
--- a/src/afserver.c
+++ b/src/afserver.c
@@ -428,9 +428,13 @@ main(int argc, char **argv)
"Setting ciphers list failed... exiting");
exit(1);
}
- if ((flags = create_apf_dir())) {
+ if ((flags = create_apf_dir(0))) {
aflog(LOG_T_INIT, LOG_I_WARNING,
"Warning: Creating ~/.apf directory failed (%d)", flags);
+ if ((flags = create_apf_dir(1))) {
+ aflog(LOG_T_INIT, LOG_I_WARNING,
+ "Warning: Creating ./apf directory failed (%d)", flags);
+ }
}
if ((flags = generate_rsa_key(&config.keys))) {
aflog(LOG_T_INIT, LOG_I_WARNING,
@@ -450,7 +454,6 @@ main(int argc, char **argv)
"Setting certificate failed (%s)... exiting", config.certif);
exit(1);
}
-
if (config.size == 0) {
aflog(LOG_T_INIT, LOG_I_CRIT,
"Working without sense is really without sense...");
@@ -964,8 +967,14 @@ main(int argc, char **argv)
len = pointer->addrlen;
sent = accept(pointer->usrclitable[l].listenfd, pointer->cliaddr, &len);
if (sent == -1) {
- aflog(LOG_T_USER, LOG_I_DDEBUG,
- "realm[%s]: listenfd: FD_ISSET --> EAGAIN", get_realmname(&config, j));
+ if (errno == EAGAIN) {
+ aflog(LOG_T_USER, LOG_I_DDEBUG,
+ "realm[%s]: listenfd: FD_ISSET --> EAGAIN", get_realmname(&config, j));
+ }
+ else {
+ aflog(LOG_T_USER, LOG_I_DDEBUG,
+ "realm[%s]: listenfd: FD_ISSET --> errno=%d", get_realmname(&config, j), errno);
+ }
continue;
}
flags = fcntl(sent, F_GETFL, 0);
@@ -1033,8 +1042,14 @@ main(int argc, char **argv)
len = pointer->addrlen;
sent = accept(pointer->clitable[k].listenfd, pointer->cliaddr, &len);
if (sent == -1) {
- aflog(LOG_T_USER, LOG_I_DDEBUG,
- "realm[%s]: listenfd: FD_ISSET --> EAGAIN", get_realmname(&config, j));
+ if (errno == EAGAIN) {
+ aflog(LOG_T_USER, LOG_I_DDEBUG,
+ "realm[%s]: listenfd: FD_ISSET --> EAGAIN", get_realmname(&config, j));
+ }
+ else {
+ aflog(LOG_T_USER, LOG_I_DDEBUG,
+ "realm[%s]: listenfd: FD_ISSET --> errno=%d", get_realmname(&config, j), errno);
+ }
continue;
}
flags = fcntl(sent, F_GETFL, 0);
@@ -1854,8 +1869,14 @@ main(int argc, char **argv)
sent = accept(pointer->usrclitable[l].managefd, pointer->cliaddr, &len);
#endif
if (sent == -1) {
- aflog(LOG_T_USER, LOG_I_DDEBUG,
- "realm[%s]: listenfd: FD_ISSET --> EAGAIN", get_realmname(&config, j));
+ if (errno == EAGAIN) {
+ aflog(LOG_T_USER, LOG_I_DDEBUG,
+ "realm[%s]: managefd: FD_ISSET --> EAGAIN", get_realmname(&config, j));
+ }
+ else {
+ aflog(LOG_T_USER, LOG_I_DDEBUG,
+ "realm[%s]: managefd: FD_ISSET --> errno=%d", get_realmname(&config, j), errno);
+ }
continue;
}
flags = fcntl(sent, F_GETFL, 0);
diff --git a/src/afserver.h b/src/afserver.h
index 816185d..1c9dab5 100644
--- a/src/afserver.h
+++ b/src/afserver.h
@@ -39,6 +39,7 @@
#include "server_signals.h"
#include "usage.h"
#include "logging.h"
+#include "daemon.h"
#include <openssl/ssl.h>
#include <openssl/err.h>
diff --git a/src/base64.c b/src/base64.c
new file mode 100644
index 0000000..a3732ca
--- /dev/null
+++ b/src/base64.c
@@ -0,0 +1,250 @@
+/*
+ * active port forwarder - software for secure forwarding
+ * Copyright (C) 2003,2004,2005 jeremian <jeremian [at] poczta.fm>
+ *
+ * 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 <config.h>
+
+#include "base64.h"
+
+/*
+ * Copyright (c) 1996, 1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+int
+b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize)
+{
+ size_t datalength = 0;
+ uint8_t input[3];
+ uint8_t output[4];
+ size_t i;
+
+ while (2 < srclength) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+ srclength -= 3;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ output[3] = input[2] & 0x3f;
+ if (output[0] >= 64) return -1;
+ if (output[1] >= 64) return -1;
+ if (output[2] >= 64) return -1;
+ if (output[3] >= 64) return -1;
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Base64[output[3]];
+ }
+
+ /* Now we worry about padding. */
+ if (0 != srclength) {
+ /* Get what's left. */
+ input[0] = input[1] = input[2] = (uint8_t) '\0';
+ for (i = 0; i < srclength; i++)
+ input[i] = *src++;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ if (output[0] >= 64) return -1;
+ if (output[1] >= 64) return -1;
+ if (output[2] >= 64) return -1;
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ if (srclength == 1)
+ target[datalength++] = Pad64;
+ else
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Pad64;
+ }
+ if (datalength >= targsize)
+ return (-1);
+ target[datalength] = '\0'; /* Returned value doesn't count \0. */
+ return (int) (datalength);
+}
+
+int
+b64_pton(char const *src, uint8_t *target, size_t targsize)
+{
+ int tarindex, state, ch;
+ char *pos;
+
+ state = 0;
+ tarindex = 0;
+
+ while ((ch = *src++) != '\0') {
+ if (isspace((unsigned char)ch)) /* Skip whitespace anywhere. */
+ continue;
+
+ if (ch == Pad64)
+ break;
+
+ pos = strchr(Base64, ch);
+ if (pos == 0) {
+ /* A non-base64 character. */
+ return (-1);
+ }
+
+ switch (state) {
+ case 0:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] = (pos - Base64) << 2;
+ }
+ state = 1;
+ break;
+ case 1:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 4;
+ target[tarindex+1] = ((pos - Base64) & 0x0f)
+ << 4 ;
+ }
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 2;
+ target[tarindex+1] = ((pos - Base64) & 0x03)
+ << 6;
+ }
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64);
+ }
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /* We got a pad char. */
+ ch = *src++; /* Skip it, get next. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (-1);
+
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace((unsigned char)ch))
+ break;
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64)
+ return (-1);
+ ch = *src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace((unsigned char)ch))
+ return (-1);
+
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (target && target[tarindex] != 0)
+ return (-1);
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0)
+ return (-1);
+ }
+
+ return (tarindex);
+}
diff --git a/src/base64.h b/src/base64.h
new file mode 100644
index 0000000..0e88f78
--- /dev/null
+++ b/src/base64.h
@@ -0,0 +1,41 @@
+/*
+ * active port forwarder - software for secure forwarding
+ * Copyright (C) 2003,2004,2005 jeremian <jeremian [at] poczta.fm>
+ *
+ * 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef _JS_BASE64_H
+#define _JS_BASE64_H
+
+/* routine to encode src with base64 algorithm */
+int b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize);
+/* routine to decode src with base64 algorithm */
+int b64_pton(char const *src, uint8_t *target, size_t targsize);
+
+#endif
diff --git a/src/client_initialization.c b/src/client_initialization.c
index a5ab560..c6022ae 100644
--- a/src/client_initialization.c
+++ b/src/client_initialization.c
@@ -21,14 +21,25 @@
#include <config.h>
#include "client_initialization.h"
+#include "first_run.h"
#include "network.h"
+#include "base64.h"
+#include "ssl_routines.h"
int
initialize_client_stage1(char tunneltype, clifd* master, char* name, char* manage,
char* proxyname, char* proxyport, char ipfam, SSL_CTX* ctx, unsigned char* buff, unsigned char* pass,
- char wanttoexit)
+ char wanttoexit, char ignorepkeys)
{
- int n;
+ int n, nlen, elen, len;
+ 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;
switch (tunneltype) {
case 0: {
if (ip_connect(&(master->commfd), name, manage, ipfam)) {
@@ -82,6 +93,7 @@ initialize_client_stage1(char tunneltype, clifd* master, char* name, char* manag
break;
}
}
+
master->ssl = SSL_new(ctx);
if (SSL_set_fd(master->ssl, master->commfd) != 1) {
aflog(LOG_T_INIT, LOG_I_CRIT,
@@ -97,12 +109,80 @@ initialize_client_stage1(char tunneltype, clifd* master, char* name, char* manag
aflog(LOG_T_INIT, LOG_I_INFO,
"Trying SSL_connect");
if ((n = SSL_connect(master->ssl)) == 1) {
+ if ((server_cert = SSL_get_peer_certificate(master->ssl)) == 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(), name, 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(), name, b64_encoded);
+ break;
+ default:
+ if (ignorepkeys) {
+ 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 {
aflog(LOG_T_INIT, LOG_I_CRIT,
- "SSL_connect has failed (%d)... exiting", n);
+ "SSL_connect has failed (%d | %d)... exiting", n, SSL_get_error(master->ssl, n));
if (wanttoexit) {
exit(1);
}
diff --git a/src/client_initialization.h b/src/client_initialization.h
index b8c534a..89235c7 100644
--- a/src/client_initialization.h
+++ b/src/client_initialization.h
@@ -32,7 +32,7 @@
int initialize_client_stage1(char tunneltype, clifd* master, char* name, char* manage,
char* proxyname, char* proxyport, char ipfam, SSL_CTX* ctx, unsigned char* buff, unsigned char* pass,
- char wanttoexit);
+ char wanttoexit, char ignorepkeys);
int initialize_client_stage2(char *type, clifd* master, int* usernum, unsigned char* buff, char wanttoexit);
int initialize_client_stage3(ConnectuserT** contable, clifd* master, int usernum, int* buflength,
socklen_t* len, fd_set* allset, fd_set* wset, int* maxfdp1, char wanttoexit);
diff --git a/src/daemon.c b/src/daemon.c
new file mode 100644
index 0000000..8472d3a
--- /dev/null
+++ b/src/daemon.c
@@ -0,0 +1,61 @@
+/*
+ * active port forwarder - software for secure forwarding
+ * Copyright (C) 2003,2004,2005 jeremian <jeremian [at] poczta.fm>
+ *
+ * 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 "daemon.h"
+
+#ifndef HAVE_DAEMON
+
+#ifndef HAVE_THIS_DAEMON
+#define HAVE_THIS_DAEMON
+
+int
+daemon(int nochdir, int noclose)
+{
+ int retval;
+ if ((retval = fork()) == 0) {
+ /* child process */
+ setsid();
+ if (nochdir == 0) {
+ chdir("/");
+ }
+ if (noclose == 0) {
+ retval = open("/dev/null", O_RDWR);
+ if (retval == -1) {
+ return retval;
+ }
+ dup2(retval, STDIN_FILENO);
+ dup2(retval, STDOUT_FILENO);
+ dup2(retval, STDERR_FILENO);
+ close(retval);
+ }
+ }
+ else {
+ /* parent process */
+ if (retval == -1) {
+ return retval;
+ }
+ _exit(0);
+ }
+ return 0;
+}
+
+#endif
+
+#endif
diff --git a/src/daemon.h b/src/daemon.h
new file mode 100644
index 0000000..2994845
--- /dev/null
+++ b/src/daemon.h
@@ -0,0 +1,39 @@
+/*
+ * active port forwarder - software for secure forwarding
+ * Copyright (C) 2003,2004,2005 jeremian <jeremian [at] poczta.fm>
+ *
+ * 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.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef HAVE_DAEMON
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+# ifndef _JS_DAEMON_H
+# define _JS_DAEMON_H
+
+int daemon(int nochdir, int noclose);
+
+# endif
+
+#endif
diff --git a/src/first_run.c b/src/first_run.c
index 842a3e0..4c866c0 100644
--- a/src/first_run.c
+++ b/src/first_run.c
@@ -28,52 +28,148 @@
#include <sys/stat.h>
#include <sys/wait.h>
#include <pwd.h>
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
static char* home_dir = NULL;
+static char* home_dir_store = NULL;
static char* home_dir_key = NULL;
static char* home_dir_cer = NULL;
+typedef struct entry
+{
+ char *key;
+ unsigned char *value;
+} entryT;
+
+static
+entryT entries[6] = {
+ {"countryName", (unsigned char*) "PL"},
+ {"stateOrProvinceName", (unsigned char*) "War-Maz"},
+ {"localityName", (unsigned char*) "Olsztyn"},
+ {"organizationName", (unsigned char*) "gray-world.net"},
+ {"organizationalUnitName", (unsigned char*) "APF team"},
+ {"commonName", (unsigned char*) "Jeremian <jeremian [at] poczta [dot] fm>"},
+};
+
+static void
+callback(int i, int j, void* k)
+{
+ if (k == NULL) {
+ printf("%d", i);
+ fflush(stdout);
+ }
+}
+
+/*
+ * Name: create_apf_dir
+ * Description: creates .apf directory in ~/ or apf directory locally
+ * Arguments: type - type of the directory to create:
+ * 0 - .apf in ~/
+ * 1 - apf in current dir
+ * Returns: 0 - success
+ * 1 - problems with fetching user info
+ * 2 - home directory is not set
+ * 3 - calloc failure
+ * 4 - directory creation failure
+ */
+
int
-create_apf_dir()
+create_apf_dir(char type)
{
int length;
struct stat buf;
struct passwd *user = getpwuid(getuid());
- if (user == NULL) {
- return 1; /* some problems witch fetching user info*/
+ if (type == 0) {
+ if (user == NULL) {
+ return 1; /* some problems with fetching user info*/
+ }
+ if (user->pw_dir == NULL) {
+ return 2; /* home directory is not set? */
+ }
+ if (home_dir) {
+ free(home_dir);
+ home_dir = NULL;
+ }
+ length = strlen(user->pw_dir);
+ home_dir = calloc(1, length + 6);
+ if (home_dir == NULL) {
+ return 3; /* calloc failed */
+ }
+ strcpy(home_dir, user->pw_dir);
+ if (home_dir[length] == '/') {
+ strcpy(&home_dir[length], ".apf");
+ }
+ else {
+ strcpy(&home_dir[length], "/.apf");
+ }
+ if (stat(home_dir, &buf)) {
+ if (mkdir(home_dir, 0700)) {
+ return 4; /* creating directory failed */
+ }
+ }
}
- if (user->pw_dir == NULL) {
- return 2; /* home directory is not set? */
+ else {
+ if (home_dir) {
+ free(home_dir);
+ home_dir = NULL;
+ }
+ home_dir = calloc(1, 4);
+ if (home_dir == NULL) {
+ return 3; /* calloc failed */
+ }
+ strcpy(home_dir, "apf");
+ if (stat(home_dir, &buf)) {
+ if (mkdir(home_dir, 0700)) {
+ return 4; /* creating directory failed */
+ }
+ }
}
- if (home_dir) {
- free(home_dir);
- home_dir = NULL;
+ return 0;
+}
+
+int
+create_publickey_store(char** storefile)
+{
+ int store_length, home_length;
+ struct stat buf;
+ FILE* store_file;
+ /* check in local directory first */
+ if (stat(*storefile, &buf) == 0) {
+ return 0;
}
- length = strlen(user->pw_dir);
- home_dir = calloc(1, length + 6);
- if (home_dir == NULL) {
- return 3; /* calloc failed */
+ /* check in home_dir */
+ store_length = strlen(*storefile);
+ home_length = strlen(home_dir);
+ if (home_dir_store) {
+ free(home_dir_store);
+ home_dir_store = NULL;
}
- strcpy(home_dir, user->pw_dir);
- if (home_dir[length] == '/') {
- strcpy(&home_dir[length], ".apf");
+ home_dir_store = calloc(1, home_length + store_length + 2);
+ if (home_dir_store == NULL) {
+ return 1; /* calloc failed */
}
- else {
- strcpy(&home_dir[length], "/.apf");
+ strcpy(home_dir_store, home_dir);
+ home_dir_store[home_length] = '/';
+ strcpy(&home_dir_store[home_length+1], *storefile);
+ *storefile = home_dir_store;
+ store_file = fopen(home_dir_store, "a");
+ if (store_file == NULL) {
+ return 1;
}
- if (stat(home_dir, &buf)) {
- if (mkdir(home_dir, 0700)) {
- return 4; /* creating directory failed */
- }
+ fclose(store_file);
+ if (stat(home_dir_store, &buf) == 0) {
+ return 0;
}
- return 0;
+ return 2;
}
int
generate_rsa_key(char** keyfile)
{
- int key_length, home_length, status;
- char openssl_cmd[101];
+ int key_length, home_length;
+ RSA* rsa_key;
+ FILE* rsa_file;
struct stat buf;
/* check in local directory first */
if (stat(*keyfile, &buf) == 0) {
@@ -98,22 +194,34 @@ generate_rsa_key(char** keyfile)
return 0;
}
/* have to generate the key */
- if (snprintf(openssl_cmd, 101, "openssl genrsa -out %s 2048", home_dir_key) > 100) {
- return 2; /* string is too long */
+ printf("generating rsa key: 2048 bits\n");
+ rsa_key = RSA_generate_key(2048, 65537, callback, NULL);
+ if (RSA_check_key(rsa_key)==1) {
+ printf(" OK!\n");
}
- status = system(openssl_cmd);
- if (status == -1) {
- return -1;
+ else {
+ printf(" FAILED!\n");
+ return 1;
}
- return WEXITSTATUS(status);
+
+ rsa_file = fopen(home_dir_key, "a");
+ PEM_write_RSAPrivateKey(rsa_file, rsa_key, NULL, NULL, 0, NULL, NULL);
+ fclose(rsa_file);
+ return 0;
}
int
generate_certificate(char** cerfile, char* keyfile)
{
- int cer_length, home_length, status, tmp_fd1, tmp_fd2;
- char openssl_cmd[301];
+ int cer_length, home_length, i;
struct stat buf;
+ X509* cert;
+ X509_REQ* req;
+ X509_NAME* subj;
+ RSA* rsa_key;
+ EVP_PKEY* pkey;
+ const EVP_MD *digest;
+ FILE* fp;
/* check in local directory first */
if (stat(*cerfile, &buf) == 0) {
return 0;
@@ -137,20 +245,102 @@ generate_certificate(char** cerfile, char* keyfile)
return 0;
}
/* have to generate the certificate */
- if (snprintf(openssl_cmd, 201, "echo -e \"pl\nWar-Maz\nOlsztyn\nSHEG\nUtils productions\njeremian\njeremian@poczta.fm\" | openssl req -new -x509 -key %s -out %s -days 1095", keyfile, home_dir_cer) > 300) {
- return 2; /* string is too long */
- }
- tmp_fd1 = dup(STDOUT_FILENO);
- tmp_fd2 = dup(STDERR_FILENO);
- close(STDOUT_FILENO);
- close(STDERR_FILENO);
- status = system(openssl_cmd);
- dup2(tmp_fd1, STDOUT_FILENO);
- dup2(tmp_fd2, STDERR_FILENO);
- close(tmp_fd1);
- close(tmp_fd2);
- if (status == -1) {
- return -1;
- }
- return WEXITSTATUS(status);
+ printf("generating self signed certificate\n");
+ fp = fopen(keyfile, "r");
+ if (fp == NULL) {
+ return 2; /* can't open keyfile */
+ }
+ rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
+ fclose(fp);
+ if (rsa_key == NULL) {
+ return 3; /* can't read RSAPrivateKey */
+ }
+ pkey = EVP_PKEY_new();
+ if (pkey == NULL) {
+ return 4; /* creating new pkey failed */
+ }
+ if (EVP_PKEY_set1_RSA(pkey, rsa_key) == 0) {
+ return 5; /* setting rsa key failed */
+ }
+ req = X509_REQ_new();
+ if (req == NULL) {
+ return 6; /* creating new request failed */
+ }
+ X509_REQ_set_pubkey(req, pkey);
+ subj = X509_NAME_new();
+ if (subj == NULL) {
+ return 7; /* creating new subject name failed */
+ }
+
+ for (i = 0; i < 6; i++)
+ {
+ int nid;
+ X509_NAME_ENTRY *ent;
+
+ if ((nid = OBJ_txt2nid(entries[i].key)) == NID_undef)
+ {
+ return 8; /* finding NID for a key failed */
+ }
+ ent = X509_NAME_ENTRY_create_by_NID(NULL, nid, MBSTRING_ASC,entries[i].value, -1);
+ if (ent == NULL) {
+ return 9; /* creating name entry from NID failed */
+ }
+ if (X509_NAME_add_entry(subj, ent, -1, 0) == 0) {
+ return 10; /* adding entry to name failed */
+ }
+ }
+ if (X509_REQ_set_subject_name(req, subj) == 0) {
+ return 11; /* adding subject to request failed */
+ }
+
+ digest = EVP_sha1();
+
+ if (X509_REQ_sign(req, pkey, digest) == 0) {
+ return 12; /* signing request failed */
+ }
+
+ cert = X509_REQ_to_X509(req, 1000, pkey);
+
+ if (X509_set_version(cert, 2L) == 0) {
+ return 13; /* setting certificate version failed */
+ }
+ ASN1_INTEGER_set(X509_get_serialNumber(cert), 1);
+
+ if (cert == NULL) {
+ return 14; /* creating certificate failed */
+ }
+
+ if (X509_sign(cert, pkey, digest) == 0) {
+ return 15; /* signing failed */
+ }
+
+ fp = fopen(home_dir_cer, "w");
+ if (fp == NULL) {
+ return 16; /* writing certificate failed */
+ }
+ PEM_write_X509(fp, cert);
+ fclose(fp);
+
+ EVP_PKEY_free(pkey);
+ X509_REQ_free(req);
+ X509_free(cert);
+ return 0;
+}
+
+char*
+get_store_filename()
+{
+ return home_dir_store;
+}
+
+char*
+get_key_filename()
+{
+ return home_dir_key;
+}
+
+char*
+get_cer_filename()
+{
+ return home_dir_cer;
}
diff --git a/src/first_run.h b/src/first_run.h
index 5a36ff6..ee9d6d5 100644
--- a/src/first_run.h
+++ b/src/first_run.h
@@ -21,9 +21,13 @@
#ifndef _JS_FIRST_RUN_H
#define _JS_FIRST_RUN_H
-int create_apf_dir();
+int create_apf_dir(char type);
+int create_publickey_store(char**);
int generate_rsa_key(char**);
int generate_certificate(char**, char*);
+char* get_store_filename();
+char* get_key_filename();
+char* get_cer_filename();
#endif
diff --git a/src/http_proxy_server.c b/src/http_proxy_server.c
index a07d6ce..f98026c 100644
--- a/src/http_proxy_server.c
+++ b/src/http_proxy_server.c
@@ -258,6 +258,7 @@ http_proxy_server(void *vptr)
else {
aflog(LOG_T_MAIN, LOG_I_DEBUG,
"http proxy: New connection --> EAGAIN");
+ continue;
}
memset(tab, 0, 9000);
nothttp = 0;
diff --git a/src/inet_ntop.c b/src/inet_ntop.c
index 6d37620..cb52713 100644
--- a/src/inet_ntop.c
+++ b/src/inet_ntop.c
@@ -38,6 +38,8 @@
#include "inet_ntop.h"
+#ifndef HAVE_INET_NTOP
+
#ifndef HAVE_THIS_INET_NTOP
#define HAVE_THIS_INET_NTOP
@@ -225,3 +227,5 @@ inet_ntop6(src, dst, size)
#endif
#endif
+
+#endif
diff --git a/src/make_ssl_handshake.c b/src/make_ssl_handshake.c
index d4cdd55..ffb4ebd 100644
--- a/src/make_ssl_handshake.c
+++ b/src/make_ssl_handshake.c
@@ -108,7 +108,7 @@ get_ssl_error(clifd *cliconn, char* info, int result)
"%s(%d): unrecognized error (%d)", info, result, errno);
}
}
- if (merror == SSL_ERROR_WANT_READ) {
+ if ((merror == SSL_ERROR_WANT_READ) || (merror == SSL_ERROR_WANT_WRITE)) {
return 1;
}
return 2;
diff --git a/src/server_get.c b/src/server_get.c
index 7ada39c..5066f54 100644
--- a/src/server_get.c
+++ b/src/server_get.c
@@ -22,28 +22,79 @@
#include "server_get.h"
#include <stdlib.h>
+#include <errno.h>
int
get_new_socket(int sockfd, char type, struct sockaddr *addr, socklen_t *addrlen, char* tunneltype)
{
int tmp;
+ int n, i;
switch (type) {
case 0: {
return accept(sockfd, addr, addrlen);
break;
}
case 1: {
- if (read(sockfd, &tmp, 4) != 4) {
- return -1;
+ i = 0;
+ while (i < 4) {
+ if ((n = read(sockfd, &tmp+i, 4-i)) != (4-i)) {
+ sleep(2);
+ if ((n > 0) && (n < 4)) {
+ i += n;
+ continue;
+ }
+ if ((n == -1) && (errno == EAGAIN)) {
+ continue;
+ }
+ return -1;
+ }
+ else {
+ break;
+ }
}
- if (read(sockfd, tunneltype, 1) != 1) {
- return -1;
+ i = 0;
+ while (i < 1) {
+ if ((n = read(sockfd, tunneltype+i, 1-i)) != (1-i)) {
+ if ((n == -1) && (errno == EAGAIN)) {
+ continue;
+ }
+ return -1;
+ }
+ else {
+ break;
+ }
}
- if (read(sockfd, addrlen, 4) != 4) {
- return -1;
+ i = 0;
+ while (i < 4) {
+ if ((n = read(sockfd, addrlen+i, 4-i)) != (4-i)) {
+ if ((n > 0) && (n < 4)) {
+ i += n;
+ continue;
+ }
+ if ((n == -1) && (errno == EAGAIN)) {
+ continue;
+ }
+ return -1;
+ }
+ else {
+ break;
+ }
}
- if (read(sockfd, addr, *addrlen) != *addrlen) {
- return -1;
+ i = 0;
+ while (i < *addrlen) {
+ if ((n = read(sockfd, addr+i, (*addrlen)-i)) != ((*addrlen)-i)) {
+ if ((n > 0) && (n < *addrlen)) {
+ i += n;
+ continue;
+ }
+ if ((n == -1) && (errno == EAGAIN)) {
+ continue;
+ }
+ return -1;
+ }
+ else {
+ break;
+ }
}
return tmp;
break;
diff --git a/src/ssl_routines.c b/src/ssl_routines.c
new file mode 100644
index 0000000..29f0968
--- /dev/null
+++ b/src/ssl_routines.c
@@ -0,0 +1,81 @@
+/*
+ * active port forwarder - software for secure forwarding
+ * Copyright (C) 2003,2004,2005 jeremian <jeremian [at] poczta.fm>
+ *
+ * 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 <config.h>
+
+#include "ssl_routines.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+check_public_key(char* filename, char* hostname, char* keyhash)
+{
+ FILE* storefile;
+ char buff[256];
+ int lspaceind, i;
+
+ memset(buff, 0, 256);
+
+ storefile = fopen(filename, "r");
+ if (storefile == NULL) {
+ return SSL_PUBLIC_KEY_NOT_KNOWN;
+ }
+
+ while (fgets(buff, 256, storefile) != NULL) {
+ lspaceind = -1;
+ for (i = 0; i < 256; ++i) {
+ if (buff[i] == 0) {
+ break;
+ }
+ if (buff[i] == ' ') {
+ lspaceind = i;
+ }
+ }
+ if (lspaceind == -1) {
+ continue;
+ }
+ if (buff[strlen(buff)-1] == '\n') {
+ buff[strlen(buff)-1] = 0;
+ }
+ buff[lspaceind] = 0;
+ if (strcmp(buff, hostname) == 0) {
+ if (strcmp(&buff[lspaceind+1], keyhash) == 0) {
+ return SSL_PUBLIC_KEY_VALID;
+ }
+ else {
+ return SSL_PUBLIC_KEY_INVALID;
+ }
+ }
+ }
+ return SSL_PUBLIC_KEY_NOT_KNOWN;
+}
+
+void
+add_public_key(char* filename, char* hostname, char* keyhash)
+{
+ FILE* storefile;
+ storefile = fopen(filename, "a");
+ if (storefile == NULL) {
+ return;
+ }
+ fprintf(storefile, "%s %s\n", hostname, keyhash);
+ fclose(storefile);
+}
diff --git a/src/ssl_routines.h b/src/ssl_routines.h
new file mode 100644
index 0000000..d35a344
--- /dev/null
+++ b/src/ssl_routines.h
@@ -0,0 +1,34 @@
+/*
+ * active port forwarder - software for secure forwarding
+ * Copyright (C) 2003,2004,2005 jeremian <jeremian [at] poczta.fm>
+ *
+ * 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.
+ *
+ */
+
+#define SSL_PUBLIC_KEY_INVALID 0
+#define SSL_PUBLIC_KEY_VALID 1
+#define SSL_PUBLIC_KEY_NOT_KNOWN 2
+
+#ifndef _JS_SSL_ROUTINES_H
+#define _JS_SSL_ROUTINES_H
+
+/* check if hostname and keyhash is known */
+int check_public_key(char* filename, char* hostname, char* keyhash);
+/* add hostname and keyhash to known_hosts file */
+void add_public_key(char* filename, char* hostname, char* keyhash);
+
+#endif
+
diff --git a/src/usage.c b/src/usage.c
index 4510781..7d73f61 100644
--- a/src/usage.c
+++ b/src/usage.c
@@ -126,9 +126,12 @@ client_long_usage(char* info)
printf(" Authorization:\n\n");
printf(" -i, --id - sends the id string to afserver\n");
printf(" --pass - set the password used for client identification\n");
- printf(" (default: no password)\n\n");
+ printf(" (default: no password)\n");
+ printf(" --ignorepkeys - ignore invalid server's public keys\n\n");
printf(" Configuration:\n\n");
printf(" -k, --keyfile - the name of the file with RSA key (default: client.rsa)\n");
+ printf(" -s, --storefile - the name of the file with stored public keys\n");
+ printf(" (default: known_hosts)\n");
printf(" -D, --dateformat - format of the date printed in logs (see 'man strftime'\n");
printf(" for details) (default: %%d.%%m.%%Y %%H:%%M:%%S)\n");
printf(" -K, --keep-alive N - send keepalive packets every N seconds\n");