Previous patch

Home

Next patch

./src/ssl.c

Patch: Additional logging in NTP

+/***************************************
+
+    This is part of frox: A simple transparent FTP proxy
+    Copyright (C) 2000 James Hollingshead
+
+    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
+  
+      ssl.c -- implementation of rfc2228 AUTH/SSL/TLS security extensions.
+               Needs openssl libraries.
+
+         So far this is only tested with vsftpd. May not work with
+         anything else.
+
+  ***************************************/
+
+#include <openssl/ssl.h>
+#include <stdlib.h>
+
+#include "common.h"
+#include "control.h"
+#include "sstr.h"
+#include "ssl.h"
+
+static SSL_CTX *ctx;
+/* ------------------------------------------------------------- **
+** init ssl context
+** ------------------------------------------------------------- */
+void ssl_init(void)
+{
+  sstr *msg;
+  int i;
+
+  if(!config.usessl)
+    return;
+  if(info->greeting == FAKED || info->greeting == AWAITED) {
+    get_message(&i, &msg);
+    if(i != 220) {
+      die(INFO, "Unable to contact server in ntp", 421,
+          "Server Unable to accept connection", 0);
+    }
+    info->greetingmsg = sstr_dup(msg);
+    info->greeting = info->greeting == FAKED ? DONE : SUPPRESSED;
+  }
+
+  send_ccommand("AUTH", "TLS");
+  get_message(&i, &msg);
+  if(i != 234) {
+    write_log(IMPORT, "SSL connection refused. "
+        "Using unencrypted connection");
+    config.usessl = FALSE;
+    return;
+  }
+
+  SSL_load_error_strings();
+  SSL_library_init();
+  ctx = SSL_CTX_new(SSLv23_client_method());
+  if(!ctx)
+    die(ERROR, "Unable to initialise SSL", 0, 0, -1);
+
+  info->ssl_sc = ssl_initfd(info->server_control.fd, SSL_CTRL);
+  if(info->ssl_sc)
+    write_log(IMPORT, "SSL initialised on control connection");
+  else
+    die(ERROR, "Unable to initialise SSL", 0, 0, -1);
+
+  if(info->greeting == SUPPRESSED) {
+    send_message(220, info->greetingmsg);
+    info->greeting = DONE;
+    sstr_free(info->greetingmsg);
+  }
+}
+
+void ssl_protect_data(void)
+{
+  sstr *msg;
+  int i;
+
+  if(!config.usessl)
+    return;
+  if(!config.datassl)
+    return;
+
+  send_ccommand("PBSZ", "0");
+  get_message(&i, &msg);
+  if(i > 299 || i < 200) {
+    config.datassl = FALSE;
+    write_log(ERROR,
+        "Failed to negotiate SSL on data connection");
+    return;
+  }
+  send_ccommand("PROT", "P");
+  get_message(&i, &msg);
+  if(i > 299 || i < 200) {
+    config.datassl = FALSE;
+    write_log(ERROR,
+        "Failed to negotiate SSL on data connection");
+    return;
+  }
+  write_log(INFO, "SSL will be used on data connections");
+}
+
+/*Initialise SSL on a file descriptor if required*/
+void *ssl_initfd(int fd, int type)
+{
+  SSL *ssl;
+
+  if(!config.usessl)
+    return NULL;
+  if(type == SSL_DATA) {
+    if(config.datassl)
+      write_log(VERBOSE,
+          "Initialising ssl on data connection.");
+    else
+      return NULL;
+  }
+
+  ssl = SSL_new(ctx);
+  if(!SSL_set_fd(ssl, fd))
+    die(ERROR, "Unable to init SSL", 0, 0, -1);
+  if(type != SSL_DATA)
+    SSL_connect(ssl);
+  return (void *) ssl;
+}
+
+void ssl_shutdown(void **ssl)
+{
+  SSL *s = (SSL *) * ssl;
+  if(!s)
+    return;
+
+  SSL_shutdown(s);
+  SSL_free(s);
+  *ssl = NULL;
+}
+
+int ssl_append_read(void *ssl, sstr * buf, int len)
+{
+  int i;
+  char *tbuf;
+  SSL *s = (SSL *) ssl;
+
+  if(!len)
+    len = 4096;
+  tbuf = malloc(len);
+  if(!tbuf)
+    die(ERROR, "Malloc failure", 0, 0, -1);
+  i = SSL_read(s, tbuf, len);
+  if(i <= 0) {
+    free(tbuf);
+    if(i == 0)
+      return 0;
+    write_log(ERROR, "SSL Error %d\n", SSL_get_error(s, i));
+    return 0;  /*SSL often seems to give an error on closing */
+  }
+
+  sstr_ncat2(buf, tbuf, i);
+  free(tbuf);
+  return i;
+}
+
+int ssl_write(void *ssl, sstr * buf)
+{
+  int i;
+  SSL *s = (SSL *) ssl;
+  i = SSL_write(s, sstr_buf(buf), sstr_len(buf));
+  return i;
+}
+
+/* We need to intercept 150 messages so that we can initialise ssl on the
+ * data connection if required. We can't do it when the initial tcp data
+ * connection is made as this frequently happens before the 150 reply, the
+ * ftp server isn't ready to negotiate the ssl, and SSL_connect() blocks.
+ *
+ * We can't just call SSL_set_connect_state() because if we are downloading
+ * then frox select()s for a read on the data line, but it is the ftp client's
+ * responsibility to play the part of the SSL client and initialise the
+ * connection.
+ *
+ * We always return 0 as we never actually deal with the reply ourselves, but
+ * just need notification. We should be called first in the && list in
+ * control.c to ensure we always get it.*/
+int ssl_parsed_reply(int code, sstr * msg)
+{
+  if(code != 150)
+    return 0;
+  if(!config.usessl || !config.datassl)
+    return 0;
+  if(SSL_connect(info->ssl_sd) == -1)
+    die(ERROR, "Unable to initialise ssl connection", 0, 0, -1);
+  return 0;
+}
+-