[proftpd-dfsg] 01/03: New upstream version 1.3.5b
Francesco Lovergine
frankie at moszumanska.debian.org
Sat Dec 10 20:29:16 UTC 2016
This is an automated email from the git hooks/post-receive script.
frankie pushed a commit to branch master
in repository proftpd-dfsg.
commit 94ac34911477ee35402f5de62b6fc182b59bf016
Author: Francesco Paolo Lovergine <frankie at debian.org>
Date: Sat Dec 10 20:47:53 2016 +0100
New upstream version 1.3.5b
---
Make.rules.in | 1 +
NEWS | 23 ++++-
RELEASE_NOTES | 7 ++
configure | 22 ++++-
configure.in | 22 ++++-
contrib/dist/rpm/proftpd.spec | 2 +-
contrib/mod_geoip.c | 24 ++---
contrib/mod_ldap.c | 9 ++
contrib/mod_sftp/fxp.c | 53 ++++++++---
contrib/mod_sftp/kbdint.c | 8 +-
contrib/mod_sftp/kex.c | 201 ++++++++++++++++++++++++++++++-----------
contrib/mod_sftp/keys.c | 45 +++++----
contrib/mod_sftp/mod_sftp.c | 8 +-
contrib/mod_sftp/mod_sftp.h.in | 4 +-
contrib/mod_sftp/scp.c | 119 ++++++++++++++----------
contrib/mod_sftp/utf8.c | 6 +-
contrib/mod_sftp_pam.c | 2 +-
contrib/mod_sql_mysql.c | 12 ++-
contrib/mod_tls.c | 181 +++++++++++++++++++++++++++++++------
include/version.h | 4 +-
lib/Makefile.in | 4 +-
lib/tpl.c | 4 -
modules/Makefile.in | 4 +-
modules/mod_auth.c | 36 +++++---
modules/mod_core.c | 4 +-
modules/mod_facts.c | 69 +++++++-------
modules/mod_log.c | 26 ++++--
modules/mod_ls.c | 54 +++++++++++
modules/mod_xfer.c | 37 +++++---
src/Makefile.in | 4 +-
src/data.c | 30 ++++--
src/encode.c | 8 +-
src/fsio.c | 27 +++++-
src/ftpscrub.c | 145 -----------------------------
src/inet.c | 2 +
src/main.c | 11 ++-
src/pool.c | 59 ++++++------
src/support.c | 6 +-
tests/api/fsio.c | 16 ++++
tests/api/str.c | 3 +-
utils/Makefile.in | 4 +-
41 files changed, 841 insertions(+), 465 deletions(-)
diff --git a/Make.rules.in b/Make.rules.in
index 9f48eb4..32796d7 100644
--- a/Make.rules.in
+++ b/Make.rules.in
@@ -20,6 +20,7 @@ LDFLAGS=@LDFLAGS@ @LIBDIRS@
LIBEXECDIR=@LIBEXECDIR@
LIBS=@LIBS@ @LIBRARIES@
LIBTOOL=@LIBTOOL@
+MAKEDEPEND=makedepend -Y
RANLIB=@RANLIB@
CURSES_LIBS=@CURSES_LIBS@
diff --git a/NEWS b/NEWS
index 795323c..3c06cfd 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,3 @@
-$Id: NEWS,v 1.1597 2014-05-15 16:24:13 castaglia Exp $
-----------------------------------------------------------------------------
More details on the bugs listed below can be found by using the bug number
@@ -9,6 +8,28 @@ $Id: NEWS,v 1.1597 2014-05-15 16:24:13 castaglia Exp $
where `N' is the bug number.
-----------------------------------------------------------------------------
+1.3.5b - Released 10-Mar-2016
+--------------------------------
+- Bug 4187 - mod_geoip does not load all of the GeoIPTables properly.
+- Bug 4191 - "Incorrect string value" reported by mod_sql_mysql for some UTF8
+ characters.
+- Bug 4097 - SSH rekey fails when using RSA hostkey smaller than 2048 bits.
+- Bug 4198 - MLSD/MLST fact type "cdir" is incorrectly used for the current
+ working directory.
+- Bug 4201 - HiddenStores temporary files not removed when exceeding quota
+ using SCP.
+- Bug 4202 - MLSD lines not properly terminated with CRLF.
+- Bug 4209 - Zero-length memory allocation possible, with undefined results.
+- Bug 4210 - Avoid unbounded SFTP extended attribute key/values.
+- Bug 4212 - Ensure that FTP data transfer commands fail appropriately when
+ "RootRevoke on" is in effect.
+- Bug 4217 - Handle FTP re-authentication attempts better.
+- Bug 4223 - Permissions on files uploaded via STOU do not honor configured
+ Umask.
+- Bug 4227 - Support SFTP clients that send multiple INIT requests.
+- Bug 4230 - TLSDHParamFile directive appears ignored because unexpected DH is
+ chosen.
+
1.3.5a - Released 27-May-2015
--------------------------------
- Bug 4055 - "error setting listen fd IPV6_TCLASS: Protocol not available" log
diff --git a/RELEASE_NOTES b/RELEASE_NOTES
index bc2c7a7..e075dc7 100644
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -6,6 +6,13 @@ This file contains a description of the major changes to ProFTPD for the
releases. More information on these changes can be found in the NEWS and
ChangeLog files.
+1.3.5b
+---------
+
+ + SSH RSA hostkeys smaller than 2048 bits now work properly.
+ + MLSD response lines are now properly CRLF terminated.
+
+
1.3.5a
---------
diff --git a/configure b/configure
index 070be4e..8152a82 100755
--- a/configure
+++ b/configure
@@ -38007,6 +38007,7 @@ rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
conftest$ac_exeext conftest.$ac_ext
LIBS="$saved_libs"
+ pr_use_pthread_for_openssl="no"
if test x"$openssl_cmdline" != xno; then
if `$openssl_cmdline version 2>/dev/null 1>&2`; then
openssl_cflags=`$openssl_cmdline version -f 2>/dev/null`
@@ -38015,11 +38016,30 @@ rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
# with threads support (see Bug#3795)
for openssl_cflag in $openssl_cflags; do
if test x"$openssl_cflag" = x"-pthread"; then
- LIBS="$LIBS -pthread"
+ pr_use_pthread_for_openssl="yes"
fi
done
+
+ if test x"$pr_use_pthread_for_openssl" = xno ; then
+ # If we're on FreeBSD, AND if OpenSSL is being used, AND if
+ # openssl version -f shows no flags, then ASSUME that we do need
+ # the -pthread flag, to avoid regressions of Bug#3795.
+ if test `echo $ostype | grep -c FREEBSD` != "0" ; then
+ pr_use_pthread_for_openssl="yes"
+ fi
+ fi
fi
fi
+ else
+ # If we're on FreeBSD, AND if OpenSSL is being used, then ASSUME that we
+ # do need the -pthread flag, to avoid regressions of Bug#3795.
+ if test `echo $ostype | grep -c DFREEBSD` != "0" ; then
+ pr_use_pthread_for_openssl="yes"
+ fi
+ fi
+
+ if test x"$pr_use_pthread_for_openssl" = xyes ; then
+ LIBS="$LIBS -pthread"
fi
fi
diff --git a/configure.in b/configure.in
index be7e6ca..dc27852 100644
--- a/configure.in
+++ b/configure.in
@@ -2665,6 +2665,7 @@ if test x"$pr_use_openssl" = xyes; then
)
LIBS="$saved_libs"
+ pr_use_pthread_for_openssl="no"
if test x"$openssl_cmdline" != xno; then
if `$openssl_cmdline version 2>/dev/null 1>&2`; then
openssl_cflags=`$openssl_cmdline version -f 2>/dev/null`
@@ -2673,11 +2674,30 @@ if test x"$pr_use_openssl" = xyes; then
# with threads support (see Bug#3795)
for openssl_cflag in $openssl_cflags; do
if test x"$openssl_cflag" = x"-pthread"; then
- LIBS="$LIBS -pthread"
+ pr_use_pthread_for_openssl="yes"
fi
done
+
+ if test x"$pr_use_pthread_for_openssl" = xno ; then
+ # If we're on FreeBSD, AND if OpenSSL is being used, AND if
+ # openssl version -f shows no flags, then ASSUME that we do need
+ # the -pthread flag, to avoid regressions of Bug#3795.
+ if test `echo $ostype | grep -c FREEBSD` != "0" ; then
+ pr_use_pthread_for_openssl="yes"
+ fi
+ fi
fi
fi
+ else
+ # If we're on FreeBSD, AND if OpenSSL is being used, then ASSUME that we
+ # do need the -pthread flag, to avoid regressions of Bug#3795.
+ if test `echo $ostype | grep -c DFREEBSD` != "0" ; then
+ pr_use_pthread_for_openssl="yes"
+ fi
+ fi
+
+ if test x"$pr_use_pthread_for_openssl" = xyes ; then
+ LIBS="$LIBS -pthread"
fi
fi
diff --git a/contrib/dist/rpm/proftpd.spec b/contrib/dist/rpm/proftpd.spec
index 98c5f25..8b4328e 100644
--- a/contrib/dist/rpm/proftpd.spec
+++ b/contrib/dist/rpm/proftpd.spec
@@ -50,7 +50,7 @@
#
# NOTE: rpmbuild is really bloody stupid, and CANNOT handle a leading '#'
# character followed by a '%' character.
-%global release_cand_version a
+%global release_cand_version b
%global usecvsversion 0%{?_with_cvs:1}
diff --git a/contrib/mod_geoip.c b/contrib/mod_geoip.c
index 9936dce..a0ec648 100644
--- a/contrib/mod_geoip.c
+++ b/contrib/mod_geoip.c
@@ -1,7 +1,7 @@
/*
* ProFTPD: mod_geoip -- a module for looking up country/city/etc for clients
*
- * Copyright (c) 2010-2014 TJ Saunders
+ * Copyright (c) 2010-2015 TJ Saunders
*
* 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
@@ -36,7 +36,7 @@
* module for Apache.
*/
-#define MOD_GEOIP_VERSION "mod_geoip/0.6"
+#define MOD_GEOIP_VERSION "mod_geoip/0.7"
/* Make sure the version of proftpd is as necessary. */
#if PROFTPD_VERSION_NUMBER < 0x0001030402
@@ -388,7 +388,8 @@ static const char *get_geoip_filter_value(int filter_id) {
return NULL;
}
-static void get_geoip_tables(array_header *geoips, int filter_flags) {
+static void get_geoip_tables(array_header *geoips, int filter_flags,
+ int skip_standard) {
config_rec *c;
c = find_config(main_server->conf, CONF_PARAM, "GeoIPTable", FALSE);
@@ -406,8 +407,9 @@ static void get_geoip_tables(array_header *geoips, int filter_flags) {
/* Make sure we open tables that are marked with the default
* GEOIP_STANDARD flag, which has a value of zero.
*/
- if ((flags == GEOIP_STANDARD && filter_flags != GEOIP_STANDARD) ||
- !(flags & filter_flags)) {
+ if (flags == GEOIP_STANDARD && skip_standard == TRUE) {
+ pr_trace_msg(trace_channel, 15,
+ "skipping loading GeoIP table '%s'", path);
c = find_config_next(c, c->next, CONF_PARAM, "GeoIPTable", FALSE);
continue;
}
@@ -638,8 +640,8 @@ static void get_geoip_data(array_header *geoips, const char *ip_addr) {
case GEOIP_REGION_EDITION_REV0:
case GEOIP_REGION_EDITION_REV1: {
- GeoIPRegion *geoip_region;
- const char *region_name, *tz;
+ GeoIPRegion *geoip_region = NULL;
+ const char *region_name = NULL, *tz = NULL;
geoip_region = GeoIP_region_by_addr(gis[i], ip_addr);
#ifdef PR_USE_IPV6
@@ -681,7 +683,7 @@ static void get_geoip_data(array_header *geoips, const char *ip_addr) {
case GEOIP_CITY_EDITION_REV0:
case GEOIP_CITY_EDITION_REV1: {
- GeoIPRecord *geoip_record;
+ GeoIPRecord *geoip_record = NULL;
char area_code_str[32], lat_str[64], lon_str[64];
geoip_record = GeoIP_record_by_addr(gis[i], ip_addr);
@@ -1128,7 +1130,7 @@ MODRET set_geoiptable(cmd_rec *cmd) {
use_utf8 = TRUE;
} else {
- CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unknown GeoIP flag '",
+ CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unknown GeoIPTable flag '",
cmd->argv[i], "'", NULL));
}
}
@@ -1194,7 +1196,7 @@ static void geoip_postparse_ev(const void *event_data, void *user_data) {
filter_flags = GEOIP_MEMORY_CACHE|GEOIP_MMAP_CACHE|GEOIP_INDEX_CACHE;
pr_log_debug(DEBUG8, MOD_GEOIP_VERSION ": loading static GeoIP tables");
- get_geoip_tables(static_geoips, filter_flags);
+ get_geoip_tables(static_geoips, filter_flags, TRUE);
}
static void geoip_restart_ev(const void *event_data, void *user_data) {
@@ -1283,7 +1285,7 @@ static int geoip_sess_init(void) {
sess_geoips = make_array(tmp_pool, 0, sizeof(GeoIP *));
pr_log_debug(DEBUG8, MOD_GEOIP_VERSION ": loading session GeoIP tables");
- get_geoip_tables(sess_geoips, GEOIP_STANDARD|GEOIP_CHECK_CACHE);
+ get_geoip_tables(sess_geoips, GEOIP_CHECK_CACHE, FALSE);
if (static_geoips->nelts == 0 &&
sess_geoips->nelts == 0) {
diff --git a/contrib/mod_ldap.c b/contrib/mod_ldap.c
index 915c743..e613da5 100644
--- a/contrib/mod_ldap.c
+++ b/contrib/mod_ldap.c
@@ -64,6 +64,15 @@ static char *ldap_server;
static int ldap_port = LDAP_PORT;
#endif
+/* On some systems LDAP_OPT_DIAGNOSTIC_MESSAGE isn't there (e.g. OpenLDAP-2.3.x)
+ * but LDAP_OPT_ERROR_STRING is.
+ */
+#ifndef LDAP_OPT_DIAGNOSTIC_MESSAGE
+# ifdef LDAP_OPT_ERROR_STRING
+# define LDAP_OPT_DIAGNOSTIC_MESSAGE LDAP_OPT_ERROR_STRING
+# endif
+#endif
+
#if LDAP_API_VERSION >= 2000
# define LDAP_VALUE_T struct berval
# define LDAP_GET_VALUES(ld, entry, attr) ldap_get_values_len(ld, entry, attr)
diff --git a/contrib/mod_sftp/fxp.c b/contrib/mod_sftp/fxp.c
index 5d9ae17..82080bb 100644
--- a/contrib/mod_sftp/fxp.c
+++ b/contrib/mod_sftp/fxp.c
@@ -235,6 +235,12 @@ static size_t fxp_packet_data_allocsz = 0;
#define FXP_PACKET_DATA_DEFAULT_SZ (1024 * 16)
#define FXP_RESPONSE_DATA_DEFAULT_SZ 512
+#define FXP_MAX_PACKET_LEN (1024 * 512)
+#define FXP_MAX_EXTENDED_ATTRIBUTES 100
+
+/* Maximum length of SFTP extended attribute name OR value. */
+#define FXP_MAX_EXTENDED_ATTR_LEN 1024
+
struct fxp_extpair {
char *ext_name;
uint32_t ext_datalen;
@@ -1240,6 +1246,14 @@ static struct fxp_extpair *fxp_msg_read_extpair(pool *p, unsigned char **buf,
SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
}
+ if (namelen > FXP_MAX_EXTENDED_ATTR_LEN) {
+ (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
+ "received too-long extended attribute name (%lu > max %lu), ignoring",
+ (unsigned long) namelen, (unsigned long) FXP_MAX_EXTENDED_ATTR_LEN);
+ errno = EINVAL;
+ return NULL;
+ }
+
name = palloc(p, namelen + 1);
memcpy(name, *buf, namelen);
(*buf) += namelen;
@@ -1248,6 +1262,15 @@ static struct fxp_extpair *fxp_msg_read_extpair(pool *p, unsigned char **buf,
datalen = sftp_msg_read_int(p, buf, buflen);
if (datalen > 0) {
+ if (datalen > FXP_MAX_EXTENDED_ATTR_LEN) {
+ (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
+ "received too-long extended attribute '%s' value (%lu > max %lu), "
+ "ignoring", name, (unsigned long) datalen,
+ (unsigned long) FXP_MAX_EXTENDED_ATTR_LEN);
+ errno = EINVAL;
+ return NULL;
+ }
+
data = sftp_msg_read_data(p, buf, buflen, datalen);
} else {
@@ -2210,11 +2233,13 @@ static struct stat *fxp_attrs_read(struct fxp_packet *fxp, unsigned char **buf,
struct fxp_extpair *ext;
ext = fxp_msg_read_extpair(fxp->pool, buf, buflen);
- pr_trace_msg(trace_channel, 15,
- "protocol version %lu: read EXTENDED attribute: "
- "extension '%s' (%lu bytes of data)",
- (unsigned long) fxp_session->client_version, ext->ext_name,
- (unsigned long) ext->ext_datalen);
+ if (ext != NULL) {
+ pr_trace_msg(trace_channel, 15,
+ "protocol version %lu: read EXTENDED attribute: "
+ "extension '%s' (%lu bytes of data)",
+ (unsigned long) fxp_session->client_version, ext->ext_name,
+ (unsigned long) ext->ext_datalen);
+ }
}
}
@@ -11580,18 +11605,20 @@ int sftp_fxp_handle_packet(pool *p, void *ssh2, uint32_t channel_id,
case SFTP_SSH2_FXP_INIT:
/* If we already know the version, then the client has sent
* FXP_INIT before, and should NOT be sending it again.
+ *
+ * However, per Bug#4227, there ARE clients which do send INIT
+ * multiple times; I don't know why. And since OpenSSH handles
+ * these repeated INITs without disconnecting clients, that is the
+ * de facto expected behavior. We will do the same, but at least
+ * log about it.
*/
- if (fxp_session->client_version == 0) {
- res = fxp_handle_init(fxp);
-
- } else {
+ if (fxp_session->client_version > 0) {
(void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
- "already received SFTP INIT request from client");
- destroy_pool(fxp->pool);
- fxp_session = NULL;
- return -1;
+ "already received SFTP INIT %u request from client",
+ (unsigned int) fxp_session->client_version);
}
+ res = fxp_handle_init(fxp);
break;
case SFTP_SSH2_FXP_CLOSE:
diff --git a/contrib/mod_sftp/kbdint.c b/contrib/mod_sftp/kbdint.c
index 8cbd2a5..8ade59a 100644
--- a/contrib/mod_sftp/kbdint.c
+++ b/contrib/mod_sftp/kbdint.c
@@ -190,7 +190,7 @@ int sftp_kbdint_unregister_driver(const char *name) {
*/
int sftp_kbdint_send_challenge(const char *user, const char *instruction,
- unsigned int count, sftp_kbdint_challenge_t *challenges) {
+ uint32_t count, sftp_kbdint_challenge_t *challenges) {
register unsigned int i;
unsigned char *buf, *ptr;
uint32_t buflen, bufsz;
@@ -252,8 +252,8 @@ int sftp_kbdint_send_challenge(const char *user, const char *instruction,
return res;
}
-int sftp_kbdint_recv_response(pool *p, unsigned int expected_count,
- unsigned int *rcvd_count, const char ***responses) {
+int sftp_kbdint_recv_response(pool *p, uint32_t expected_count,
+ uint32_t *rcvd_count, const char ***responses) {
register unsigned int i;
unsigned char *buf;
cmd_rec *cmd;
@@ -330,7 +330,7 @@ int sftp_kbdint_recv_response(pool *p, unsigned int expected_count,
*((char **) push_array(list)) = pstrdup(p, sftp_utf8_decode_str(p, resp));
}
- *rcvd_count = (unsigned int) resp_count;
+ *rcvd_count = resp_count;
*responses = ((const char **) list->elts);
destroy_pool(pkt->pool);
diff --git a/contrib/mod_sftp/kex.c b/contrib/mod_sftp/kex.c
index c57191c..60b8b01 100644
--- a/contrib/mod_sftp/kex.c
+++ b/contrib/mod_sftp/kex.c
@@ -1,6 +1,6 @@
/*
* ProFTPD - mod_sftp key exchange (kex)
- * Copyright (c) 2008-2013 TJ Saunders
+ * Copyright (c) 2008-2015 TJ Saunders
*
* 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
@@ -20,8 +20,6 @@
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
- *
- * $Id: kex.c,v 1.39 2013-10-02 06:18:53 castaglia Exp $
*/
#include "mod_sftp.h"
@@ -39,8 +37,6 @@
#include "interop.h"
#include "tap.h"
-#define SFTP_DH_PRIV_KEY_RANDOM_BITS 2048
-
extern module sftp_module;
/* For managing the kexinit process */
@@ -621,8 +617,94 @@ static int have_good_dh(DH *dh, BIGNUM *pub_key) {
return 0;
}
+static int get_dh_nbits(struct sftp_kex *kex) {
+ int dh_nbits = 0, dh_size = 0;
+ const char *algo;
+ const EVP_CIPHER *cipher;
+ const EVP_MD *digest;
+
+ algo = kex->session_names->c2s_encrypt_algo;
+ cipher = sftp_crypto_get_cipher(algo, NULL, NULL);
+ if (cipher != NULL) {
+ int block_size, key_len;
+
+ key_len = EVP_CIPHER_key_length(cipher);
+ if (dh_size < key_len) {
+ dh_size = key_len;
+ pr_trace_msg(trace_channel, 19,
+ "set DH size to %d bytes, matching client-to-server '%s' cipher "
+ "key length", dh_size, algo);
+ }
+
+ block_size = EVP_CIPHER_block_size(cipher);
+ if (dh_size < block_size) {
+ dh_size = block_size;
+ pr_trace_msg(trace_channel, 19,
+ "set DH size to %d bytes, matching client-to-server '%s' cipher "
+ "block size", dh_size, algo);
+ }
+ }
+
+ algo = kex->session_names->s2c_encrypt_algo;
+ cipher = sftp_crypto_get_cipher(algo, NULL, NULL);
+ if (cipher != NULL) {
+ int block_size, key_len;
+
+ key_len = EVP_CIPHER_key_length(cipher);
+ if (dh_size < key_len) {
+ dh_size = key_len;
+ pr_trace_msg(trace_channel, 19,
+ "set DH size to %d bytes, matching server-to-client '%s' cipher "
+ "key length", dh_size, algo);
+ }
+
+ block_size = EVP_CIPHER_block_size(cipher);
+ if (dh_size < block_size) {
+ dh_size = block_size;
+ pr_trace_msg(trace_channel, 19,
+ "set DH size to %d bytes, matching server-to-client '%s' cipher "
+ "block size", dh_size, algo);
+ }
+ }
+
+ algo = kex->session_names->c2s_mac_algo;
+ digest = sftp_crypto_get_digest(algo, NULL);
+ if (digest != NULL) {
+ int mac_len;
+
+ mac_len = EVP_MD_size(digest);
+ if (dh_size < mac_len) {
+ dh_size = mac_len;
+ pr_trace_msg(trace_channel, 19,
+ "set DH size to %d bytes, matching client-to-server '%s' digest size",
+ dh_size, algo);
+ }
+ }
+
+ algo = kex->session_names->s2c_mac_algo;
+ digest = sftp_crypto_get_digest(algo, NULL);
+ if (digest != NULL) {
+ int mac_len;
+
+ mac_len = EVP_MD_size(digest);
+ if (dh_size < mac_len) {
+ dh_size = mac_len;
+ pr_trace_msg(trace_channel, 19,
+ "set DH size to %d bytes, matching server-to-client '%s' digest size",
+ dh_size, algo);
+ }
+ }
+
+ /* We want to return bits, not bytes. */
+ dh_nbits = dh_size * 8;
+
+ pr_trace_msg(trace_channel, 8, "requesting DH size of %d bits", dh_nbits);
+ return dh_nbits;
+}
+
static int create_dh(struct sftp_kex *kex, int type) {
unsigned int attempts = 0;
+ int dh_nbits;
DH *dh;
if (type != SFTP_DH_GROUP1_SHA1 &&
@@ -656,6 +738,8 @@ static int create_dh(struct sftp_kex *kex, int type) {
kex->dh = NULL;
}
+ dh_nbits = get_dh_nbits(kex);
+
/* We have 10 attempts to make a DH key which passes muster. */
while (attempts <= 10) {
pr_signals_handle();
@@ -665,7 +749,7 @@ static int create_dh(struct sftp_kex *kex, int type) {
attempts);
dh = DH_new();
- if (!dh) {
+ if (dh == NULL) {
(void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
"error creating DH: %s", sftp_crypto_get_errors());
return -1;
@@ -699,10 +783,11 @@ static int create_dh(struct sftp_kex *kex, int type) {
return -1;
}
- if (!BN_rand(dh->priv_key, SFTP_DH_PRIV_KEY_RANDOM_BITS, 0, 0)) {
+ /* Generate a random private exponent of the desired size, in bits. */
+ if (!BN_rand(dh->priv_key, dh_nbits, 0, 0)) {
(void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
- "error generating DH random key (%d bytes): %s",
- SFTP_DH_PRIV_KEY_RANDOM_BITS, sftp_crypto_get_errors());
+ "error generating DH random key (%d bits): %s", dh_nbits,
+ sftp_crypto_get_errors());
DH_free(dh);
return -1;
}
@@ -787,6 +872,9 @@ static int prepare_dh(struct sftp_kex *kex, int type) {
static int finish_dh(struct sftp_kex *kex) {
unsigned int attempts = 0;
+ int dh_nbits;
+
+ dh_nbits = get_dh_nbits(kex);
/* We have 10 attempts to make a DH key which passes muster. */
while (attempts <= 10) {
@@ -797,11 +885,12 @@ static int finish_dh(struct sftp_kex *kex) {
attempts);
kex->dh->priv_key = BN_new();
-
- if (!BN_rand(kex->dh->priv_key, SFTP_DH_PRIV_KEY_RANDOM_BITS, 0, 0)) {
+
+ /* Generate a random private exponent of the desired size, in bits. */
+ if (!BN_rand(kex->dh->priv_key, dh_nbits, 0, 0)) {
(void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
- "error generating DH random key (%d bytes): %s",
- SFTP_DH_PRIV_KEY_RANDOM_BITS, sftp_crypto_get_errors());
+ "error generating DH random key (%d bits): %s", dh_nbits,
+ sftp_crypto_get_errors());
return -1;
}
@@ -1514,77 +1603,71 @@ static int setup_hostkey_algo(struct sftp_kex *kex, const char *algo) {
}
static int setup_c2s_encrypt_algo(struct sftp_kex *kex, const char *algo) {
- (void) kex;
-
- if (sftp_cipher_set_read_algo(algo) < 0)
+ if (sftp_cipher_set_read_algo(algo) < 0) {
return -1;
+ }
+ kex->session_names->c2s_encrypt_algo = algo;
return 0;
}
static int setup_s2c_encrypt_algo(struct sftp_kex *kex, const char *algo) {
- (void) kex;
-
- if (sftp_cipher_set_write_algo(algo) < 0)
+ if (sftp_cipher_set_write_algo(algo) < 0) {
return -1;
+ }
+ kex->session_names->s2c_encrypt_algo = algo;
return 0;
}
static int setup_c2s_mac_algo(struct sftp_kex *kex, const char *algo) {
- (void) kex;
-
- if (sftp_mac_set_read_algo(algo) < 0)
+ if (sftp_mac_set_read_algo(algo) < 0) {
return -1;
+ }
+ kex->session_names->c2s_mac_algo = algo;
return 0;
}
static int setup_s2c_mac_algo(struct sftp_kex *kex, const char *algo) {
- (void) kex;
-
- if (sftp_mac_set_write_algo(algo) < 0)
+ if (sftp_mac_set_write_algo(algo) < 0) {
return -1;
+ }
+ kex->session_names->s2c_mac_algo = algo;
return 0;
}
static int setup_c2s_comp_algo(struct sftp_kex *kex, const char *algo) {
- (void) kex;
-
- if (sftp_compress_set_read_algo(algo) < 0)
+ if (sftp_compress_set_read_algo(algo) < 0) {
return -1;
+ }
+ kex->session_names->c2s_comp_algo = algo;
return 0;
}
static int setup_s2c_comp_algo(struct sftp_kex *kex, const char *algo) {
- (void) kex;
-
- if (sftp_compress_set_write_algo(algo) < 0)
+ if (sftp_compress_set_write_algo(algo) < 0) {
return -1;
+ }
+ kex->session_names->s2c_comp_algo = algo;
return 0;
}
static int setup_c2s_lang(struct sftp_kex *kex, const char *lang) {
- (void) kex;
-
- /* XXX Need to implement the functionality here. */
-
+ kex->session_names->c2s_lang = lang;
return 0;
}
static int setup_s2c_lang(struct sftp_kex *kex, const char *lang) {
- (void) kex;
-
- /* XXX Need to implement the functionality here. */
-
+ kex->session_names->s2c_lang = lang;
return 0;
}
static int get_session_names(struct sftp_kex *kex, int *correct_guess) {
- const char *shared, *client_list, *server_list;
+ const char *kex_algo, *shared, *client_list, *server_list;
const char *client_pref, *server_pref;
pool *tmp_pool;
@@ -1624,17 +1707,16 @@ static int get_session_names(struct sftp_kex *kex, int *correct_guess) {
}
}
- shared = get_shared_name(kex_pool, client_list, server_list);
- if (shared) {
- if (setup_kex_algo(kex, shared) < 0) {
- destroy_pool(tmp_pool);
- return -1;
- }
-
+ kex_algo = get_shared_name(kex_pool, client_list, server_list);
+ if (kex_algo != NULL) {
+ /* Unlike the following algorithms, we wait to setup the chosen kex algo
+ * until the end. Why? The kex algo setup may require knowledge of the
+ * ciphers chosen for encryption, MAC, etc (Bug#4097).
+ */
(void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
- " + Session key exchange: %s", shared);
+ " + Session key exchange: %s", kex_algo);
pr_trace_msg(trace_channel, 20, "session key exchange algorithm: %s",
- shared);
+ kex_algo);
} else {
(void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
@@ -1902,6 +1984,14 @@ static int get_session_names(struct sftp_kex *kex, int *correct_guess) {
#endif
}
+ /* Now that we've finished setting up the other bits, we can set up the
+ * kex algo.
+ */
+ if (setup_kex_algo(kex, kex_algo) < 0) {
+ destroy_pool(tmp_pool);
+ return -1;
+ }
+
destroy_pool(tmp_pool);
return 0;
}
@@ -3659,12 +3749,6 @@ int sftp_kex_handle(struct ssh2_packet *pkt) {
pkt = read_kex_packet(kex_pool, kex, SFTP_SSH2_DISCONNECT_PROTOCOL_ERROR,
NULL, 1, SFTP_SSH2_MSG_NEWKEYS);
- cmd = pr_cmd_alloc(pkt->pool, 1, pstrdup(pkt->pool, "NEWKEYS"));
- cmd->arg = "";
- cmd->cmd_class = CL_AUTH;
-
- pr_cmd_dispatch_phase(cmd, LOG_CMD, 0);
-
/* If we didn't send our NEWKEYS message earlier, do it now. */
if (!sent_newkeys) {
pr_trace_msg(trace_channel, 9, "sending NEWKEYS message to client");
@@ -3699,6 +3783,13 @@ int sftp_kex_handle(struct ssh2_packet *pkt) {
SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
}
+ cmd = pr_cmd_alloc(pkt->pool, 1, pstrdup(pkt->pool, "NEWKEYS"));
+ cmd->arg = "";
+ cmd->cmd_class = CL_AUTH;
+
+ pr_cmd_dispatch_phase(cmd, LOG_CMD, 0);
+ destroy_pool(pkt->pool);
+
/* Reset this flag for the next time through. */
kex_sent_kexinit = FALSE;
diff --git a/contrib/mod_sftp/keys.c b/contrib/mod_sftp/keys.c
index 1247ea6..371de28 100644
--- a/contrib/mod_sftp/keys.c
+++ b/contrib/mod_sftp/keys.c
@@ -1,6 +1,6 @@
/*
* ProFTPD - mod_sftp key mgmt (keys)
- * Copyright (c) 2008-2014 TJ Saunders
+ * Copyright (c) 2008-2015 TJ Saunders
*
* 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
@@ -20,8 +20,6 @@
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
- *
- * $Id: keys.c,v 1.39 2014-01-28 17:26:17 castaglia Exp $
*/
#include "mod_sftp.h"
@@ -36,6 +34,7 @@
extern xaset_t *server_list;
extern module sftp_module;
+/* Note: Should this size be made bigger, in light of larger hostkeys? */
#define SFTP_DEFAULT_HOSTKEY_SZ 4096
#define SFTP_MAX_SIG_SZ 4096
@@ -2022,7 +2021,7 @@ const unsigned char *sftp_keys_get_hostkey_data(pool *p,
}
/* XXX Is this buffer large enough? Too large? */
- ptr = buf = sftp_msg_getbuf(p, buflen);
+ ptr = buf = palloc(p, buflen);
sftp_msg_write_string(&buf, &buflen, "ssh-rsa");
sftp_msg_write_mpint(&buf, &buflen, rsa->e);
sftp_msg_write_mpint(&buf, &buflen, rsa->n);
@@ -2042,7 +2041,7 @@ const unsigned char *sftp_keys_get_hostkey_data(pool *p,
}
/* XXX Is this buffer large enough? Too large? */
- ptr = buf = sftp_msg_getbuf(p, buflen);
+ ptr = buf = palloc(p, buflen);
sftp_msg_write_string(&buf, &buflen, "ssh-dss");
sftp_msg_write_mpint(&buf, &buflen, dsa->p);
sftp_msg_write_mpint(&buf, &buflen, dsa->q);
@@ -2065,8 +2064,7 @@ const unsigned char *sftp_keys_get_hostkey_data(pool *p,
}
/* XXX Is this buffer large enough? Too large? */
- ptr = buf = sftp_msg_getbuf(p, buflen);
-
+ ptr = buf = palloc(p, buflen);
sftp_msg_write_string(&buf, &buflen, "ecdsa-sha2-nistp256");
sftp_msg_write_string(&buf, &buflen, "nistp256");
sftp_msg_write_ecpoint(&buf, &buflen, EC_KEY_get0_group(ec),
@@ -2087,8 +2085,7 @@ const unsigned char *sftp_keys_get_hostkey_data(pool *p,
}
/* XXX Is this buffer large enough? Too large? */
- ptr = buf = sftp_msg_getbuf(p, buflen);
-
+ ptr = buf = palloc(p, buflen);
sftp_msg_write_string(&buf, &buflen, "ecdsa-sha2-nistp384");
sftp_msg_write_string(&buf, &buflen, "nistp384");
sftp_msg_write_ecpoint(&buf, &buflen, EC_KEY_get0_group(ec),
@@ -2109,8 +2106,7 @@ const unsigned char *sftp_keys_get_hostkey_data(pool *p,
}
/* XXX Is this buffer large enough? Too large? */
- ptr = buf = sftp_msg_getbuf(p, buflen);
-
+ ptr = buf = palloc(p, buflen);
sftp_msg_write_string(&buf, &buflen, "ecdsa-sha2-nistp521");
sftp_msg_write_string(&buf, &buflen, "nistp521");
sftp_msg_write_ecpoint(&buf, &buflen, EC_KEY_get0_group(ec),
@@ -2131,8 +2127,14 @@ const unsigned char *sftp_keys_get_hostkey_data(pool *p,
*datalen = SFTP_DEFAULT_HOSTKEY_SZ - buflen;
/* If the caller provided a pool, make a copy of the data from the
- * given pool, and return the copy. Make sure the scrub the original
+ * given pool, and return the copy. Make sure to scrub the original
* after making the copy.
+ *
+ * Note that we do this copy, even though we use the given pool, since
+ * we only know the actual size of the data after the fact. And we need
+ * to provide the size of the data to the caller, NOT the optimistic size
+ * we allocate out of the pool for writing the data in the first place.
+ * Hence the copy.
*/
if (p) {
buf = palloc(p, *datalen);
@@ -2161,27 +2163,38 @@ int sftp_keys_have_ecdsa_hostkey(pool *p, int **nids) {
#ifdef PR_USE_OPENSSL_ECC
int count = 0;
- *nids = palloc(p, sizeof(int) * 3);
+ if (nids != NULL) {
+ *nids = palloc(p, sizeof(int) * 3);
+ }
if (sftp_ecdsa256_hostkey != NULL) {
EC_KEY *ec;
ec = EVP_PKEY_get1_EC_KEY(sftp_ecdsa256_hostkey->pkey);
- (*nids)[count++] = get_ecdsa_nid(ec);
+ if (nids != NULL) {
+ (*nids)[count] = get_ecdsa_nid(ec);
+ }
+ count++;
EC_KEY_free(ec);
} else if (sftp_ecdsa384_hostkey != NULL) {
EC_KEY *ec;
ec = EVP_PKEY_get1_EC_KEY(sftp_ecdsa384_hostkey->pkey);
- (*nids)[count++] = get_ecdsa_nid(ec);
+ if (nids != NULL) {
+ (*nids)[count] = get_ecdsa_nid(ec);
+ }
+ count++;
EC_KEY_free(ec);
} else if (sftp_ecdsa521_hostkey != NULL) {
EC_KEY *ec;
ec = EVP_PKEY_get1_EC_KEY(sftp_ecdsa521_hostkey->pkey);
- (*nids)[count++] = get_ecdsa_nid(ec);
+ if (nids != NULL) {
+ (*nids)[count] = get_ecdsa_nid(ec);
+ }
+ count++;
EC_KEY_free(ec);
}
diff --git a/contrib/mod_sftp/mod_sftp.c b/contrib/mod_sftp/mod_sftp.c
index bc733ee..95cbd9d 100644
--- a/contrib/mod_sftp/mod_sftp.c
+++ b/contrib/mod_sftp/mod_sftp.c
@@ -1,6 +1,6 @@
/*
* ProFTPD - mod_sftp
- * Copyright (c) 2008-2014 TJ Saunders
+ * Copyright (c) 2008-2015 TJ Saunders
*
* 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
@@ -21,10 +21,9 @@
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*
- * DO NOT EDIT BELOW THIS LINE
+ * -----DO NOT EDIT BELOW THIS LINE-----
* $Archive: mod_sftp.a $
* $Libraries: -lcrypto -lz $
- * $Id: mod_sftp.c,v 1.86 2014-03-02 22:05:43 castaglia Exp $
*/
#include "mod_sftp.h"
@@ -1764,7 +1763,8 @@ static int sftp_sess_init(void) {
* we have to have at least one hostkey.
*/
if (sftp_keys_have_dsa_hostkey() < 0 &&
- sftp_keys_have_rsa_hostkey() < 0) {
+ sftp_keys_have_rsa_hostkey() < 0 &&
+ sftp_keys_have_ecdsa_hostkey(sftp_pool, NULL) < 0) {
(void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
"no available host keys, unable to handle session");
errno = EACCES;
diff --git a/contrib/mod_sftp/mod_sftp.h.in b/contrib/mod_sftp/mod_sftp.h.in
index a020a29..1765bde 100644
--- a/contrib/mod_sftp/mod_sftp.h.in
+++ b/contrib/mod_sftp/mod_sftp.h.in
@@ -180,9 +180,9 @@ typedef struct kbdint_st {
int sftp_kbdint_register_driver(const char *name, sftp_kbdint_driver_t *driver);
int sftp_kbdint_unregister_driver(const char *name);
-int sftp_kbdint_send_challenge(const char *, const char *, unsigned int,
+int sftp_kbdint_send_challenge(const char *, const char *, uint32_t,
sftp_kbdint_challenge_t *);
-int sftp_kbdint_recv_response(pool *, unsigned int, unsigned int *,
+int sftp_kbdint_recv_response(pool *, uint32_t, uint32_t *,
const char ***);
/* API for modules that which to register keystores, for the
diff --git a/contrib/mod_sftp/scp.c b/contrib/mod_sftp/scp.c
index 03b83da..6186805 100644
--- a/contrib/mod_sftp/scp.c
+++ b/contrib/mod_sftp/scp.c
@@ -1,6 +1,6 @@
/*
* ProFTPD - mod_sftp SCP
- * Copyright (c) 2008-2014 TJ Saunders
+ * Copyright (c) 2008-2015 TJ Saunders
*
* 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
@@ -20,8 +20,6 @@
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
- *
- * $Id: scp.c,v 1.87 2014-01-20 20:49:04 castaglia Exp $
*/
#include "mod_sftp.h"
@@ -1054,8 +1052,9 @@ static int recv_data(pool *p, uint32_t channel_id, struct scp_path *sp,
pstrcat(p, sp->filename, ": write error: ", strerror(xerrno), NULL));
sp->wrote_errors = TRUE;
- pr_fsio_close(sp->fh);
- sp->fh = NULL;
+ /* Note that we do NOT explicitly close the filehandle here; we leave
+ * that to the calling function, so that it can do e.g. other cleanup.
+ */
errno = xerrno;
return 1;
@@ -1080,8 +1079,9 @@ static int recv_data(pool *p, uint32_t channel_id, struct scp_path *sp,
pstrcat(p, sp->filename, ": write error: ", strerror(xerrno), NULL));
sp->wrote_errors = TRUE;
- pr_fsio_close(sp->fh);
- sp->fh = NULL;
+ /* Note that we do NOT explicitly close the filehandle here; we leave
+ * that to the calling function, so that it can do e.g. other cleanup.
+ */
errno = xerrno;
return 1;
@@ -1217,6 +1217,7 @@ static int recv_path(pool *p, uint32_t channel_id, struct scp_path *sp,
unsigned char *data, uint32_t datalen) {
int res;
cmd_rec *cmd = NULL;
+ char *curr_path = NULL;
if (!sp->checked_errors) {
res = recv_errors(p, channel_id, sp, data, datalen);
@@ -1367,53 +1368,55 @@ static int recv_path(pool *p, uint32_t channel_id, struct scp_path *sp,
}
}
- /* The uploaded file may be smaller than an existing file; call
- * pr_fsio_truncate() to ensure proper file size.
- */
- if (S_ISREG(sp->st_mode)) {
- pr_trace_msg(trace_channel, 9, "truncating file '%s' to %" PR_LU " bytes",
- sp->fh->fh_path, (pr_off_t) sp->filesz);
+ if (sp->wrote_errors == FALSE) {
+ /* The uploaded file may be smaller than an existing file; call
+ * pr_fsio_truncate() to ensure proper file size.
+ */
+ if (S_ISREG(sp->st_mode)) {
+ pr_trace_msg(trace_channel, 9, "truncating file '%s' to %" PR_LU " bytes",
+ sp->fh->fh_path, (pr_off_t) sp->filesz);
- if (pr_fsio_ftruncate(sp->fh, sp->filesz) < 0) {
- int xerrno = errno;
+ if (pr_fsio_ftruncate(sp->fh, sp->filesz) < 0) {
+ int xerrno = errno;
- pr_trace_msg(trace_channel, 2, "error truncating '%s' to %" PR_LU
- " bytes: %s", sp->best_path, (pr_off_t) sp->filesz, strerror(xerrno));
- write_confirm(p, channel_id, 1,
- pstrcat(p, sp->filename, ": error truncating file: ", strerror(xerrno),
- NULL));
+ pr_trace_msg(trace_channel, 2, "error truncating '%s' to %" PR_LU
+ " bytes: %s", sp->best_path, (pr_off_t) sp->filesz, strerror(xerrno));
+ write_confirm(p, channel_id, 1,
+ pstrcat(p, sp->filename, ": error truncating file: ",
+ strerror(xerrno), NULL));
- sp->wrote_errors = TRUE;
+ sp->wrote_errors = TRUE;
+ }
}
}
- /* If the SFTPOption for ignoring perms for SCP uploads is set, then
- * skip the chmod on the upload file.
- */
- if (!(sftp_opts & SFTP_OPT_IGNORE_SCP_UPLOAD_PERMS)) {
- pr_trace_msg(trace_channel, 9, "setting perms %04o on file '%s'",
- (unsigned int) sp->perms, sp->fh->fh_path);
+ if (sp->wrote_errors == FALSE) {
+ /* If the SFTPOption for ignoring perms for SCP uploads is set, then
+ * skip the chmod on the upload file.
+ */
+ if (!(sftp_opts & SFTP_OPT_IGNORE_SCP_UPLOAD_PERMS)) {
+ pr_trace_msg(trace_channel, 9, "setting perms %04o on file '%s'",
+ (unsigned int) sp->perms, sp->fh->fh_path);
- if (pr_fsio_fchmod(sp->fh, sp->perms) < 0) {
- int xerrno = errno;
+ if (pr_fsio_fchmod(sp->fh, sp->perms) < 0) {
+ int xerrno = errno;
- pr_trace_msg(trace_channel, 2, "error setting mode %04o on '%s': %s",
- (unsigned int) sp->perms, sp->best_path, strerror(xerrno));
- write_confirm(p, channel_id, 1,
- pstrcat(p, sp->filename, ": error setting mode: ", strerror(xerrno),
- NULL));
+ pr_trace_msg(trace_channel, 2, "error setting mode %04o on '%s': %s",
+ (unsigned int) sp->perms, sp->best_path, strerror(xerrno));
+ write_confirm(p, channel_id, 1,
+ pstrcat(p, sp->filename, ": error setting mode: ", strerror(xerrno),
+ NULL));
- sp->wrote_errors = TRUE;
- }
+ sp->wrote_errors = TRUE;
+ }
- } else {
- pr_trace_msg(trace_channel, 7, "SFTPOption 'IgnoreSCPUploadPerms' "
- "configured, ignoring perms sent by client");
+ } else {
+ pr_trace_msg(trace_channel, 7, "SFTPOption 'IgnoreSCPUploadPerms' "
+ "configured, ignoring perms sent by client");
+ }
}
if (sp->fh) {
- char *curr_path;
-
curr_path = pstrdup(scp_pool, sp->fh->fh_path);
/* Set session.curr_cmd, for any FSIO callbacks that might be interested. */
@@ -1432,15 +1435,33 @@ static int recv_path(pool *p, uint32_t channel_id, struct scp_path *sp,
}
sp->fh = NULL;
+ }
+
+ if (sp->hiddenstore == TRUE &&
+ curr_path != NULL) {
+
+ if (sp->wrote_errors == TRUE) {
+ /* There was an error writing this HiddenStores file; be sure to clean
+ * things up.
+ */
+ pr_trace_msg(trace_channel, 8, "deleting HiddenStores path '%s'",
+ curr_path);
- if (sp->hiddenstore == TRUE &&
- res == 0) {
+ if (pr_fsio_unlink(curr_path) < 0) {
+ if (errno != ENOENT) {
+ pr_log_debug(DEBUG0, MOD_SFTP_VERSION
+ ": error deleting HiddenStores file '%s': %s", curr_path,
+ strerror(errno));
+ }
+ }
+
+ } else {
/* This is a HiddenStores file, and needs to be renamed to the real
* path (i.e. sp->best_path).
*/
- pr_trace_msg(trace_channel, 8, "renaming HiddenStores path '%s' to '%s'",
- curr_path, sp->best_path);
+ pr_trace_msg(trace_channel, 8,
+ "renaming HiddenStores path '%s' to '%s'", curr_path, sp->best_path);
res = pr_fsio_rename(curr_path, sp->best_path);
if (res < 0) {
@@ -1453,7 +1474,13 @@ static int recv_path(pool *p, uint32_t channel_id, struct scp_path *sp,
"renaming of HiddenStore path '%s' to '%s' failed: %s",
curr_path, sp->best_path, strerror(xerrno));
- pr_fsio_unlink(curr_path);
+ if (pr_fsio_unlink(curr_path) < 0) {
+ if (errno != ENOENT) {
+ pr_trace_msg(trace_channel, 1,
+ "error deleting HiddenStores file '%s': %s", curr_path,
+ strerror(errno));
+ }
+ }
}
}
}
diff --git a/contrib/mod_sftp/utf8.c b/contrib/mod_sftp/utf8.c
index 549b3d5..b11c96f 100644
--- a/contrib/mod_sftp/utf8.c
+++ b/contrib/mod_sftp/utf8.c
@@ -1,6 +1,6 @@
/*
* ProFTPD - mod_sftp UTF8 encoding
- * Copyright (c) 2008-2013 TJ Saunders
+ * Copyright (c) 2008-2015 TJ Saunders
*
* 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
@@ -20,8 +20,6 @@
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
- *
- * $Id: utf8.c,v 1.18 2013-01-29 06:51:11 castaglia Exp $
*/
#include "mod_sftp.h"
@@ -58,7 +56,7 @@ static int utf8_convert(iconv_t conv, const char *inbuf, size_t *inbuflen,
*/
#if defined(LINUX) || defined(DARWIN6) || defined(DARWIN7) || \
defined(DARWIN8) || defined(DARWIN9) || defined(DARWIN10) || \
- defined(DARWIN11)
+ defined(DARWIN11) || defined(DARWIN12)
nconv = iconv(conv, (char **) &inbuf, inbuflen, &outbuf, outbuflen);
#else
diff --git a/contrib/mod_sftp_pam.c b/contrib/mod_sftp_pam.c
index 1b757fa..44c1022 100644
--- a/contrib/mod_sftp_pam.c
+++ b/contrib/mod_sftp_pam.c
@@ -119,7 +119,7 @@ static int sftppam_converse(int nmsgs, PR_PAM_CONST struct pam_message **msgs,
struct pam_response **resps, void *app_data) {
register unsigned int i = 0, j = 0;
array_header *list;
- unsigned int recvd_count = 0;
+ uint32_t recvd_count = 0;
const char **recvd_responses = NULL;
struct pam_response *res = NULL;
diff --git a/contrib/mod_sql_mysql.c b/contrib/mod_sql_mysql.c
index b50847d..d836a01 100644
--- a/contrib/mod_sql_mysql.c
+++ b/contrib/mod_sql_mysql.c
@@ -1,7 +1,7 @@
/*
* ProFTPD: mod_sql_mysql -- Support for connecting to MySQL databases.
* Copyright (c) 2001 Andrew Houghton
- * Copyright (c) 2004-2013 TJ Saunders
+ * Copyright (c) 2004-2015 TJ Saunders
*
* 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
@@ -22,10 +22,7 @@
* the resulting executable, without including the source code for OpenSSL in
* the source distribution.
*
- * $Id: mod_sql_mysql.c,v 1.72 2013-10-07 05:51:29 castaglia Exp $
- */
-
-/*
+ * -----DO NOT EDIT-----
* $Libraries: -lm -lmysqlclient -lz $
*/
@@ -538,8 +535,13 @@ MODRET cmd_open(cmd_rec *cmd) {
*/
if (strcasecmp(encoding, "UTF-8") == 0) {
+# if MYSQL_VERSION_ID >= 50503
+ /* MySQL prefers the name "utf8mb4", not "UTF-8" */
+ encoding = pstrdup(cmd->tmp_pool, "utf8mb4");
+# else
/* MySQL prefers the name "utf8", not "UTF-8" */
encoding = pstrdup(cmd->tmp_pool, "utf8");
+# endif /* MySQL before 5.5.3 */
}
if (mysql_set_character_set(conn->mysql, encoding) != 0) {
diff --git a/contrib/mod_tls.c b/contrib/mod_tls.c
index df92658..ecd9f56 100644
--- a/contrib/mod_tls.c
+++ b/contrib/mod_tls.c
@@ -2,7 +2,7 @@
* mod_tls - An RFC2228 SSL/TLS module for ProFTPD
*
* Copyright (c) 2000-2002 Peter 'Luna' Runestig <peter at runestig.com>
- * Copyright (c) 2002-2014 TJ Saunders <tj at castaglia.org>
+ * Copyright (c) 2002-2016 TJ Saunders <tj at castaglia.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifi-
@@ -411,6 +411,13 @@ static int tls_required_on_ctrl = 0;
static int tls_required_on_data = 0;
static unsigned char *tls_authenticated = NULL;
+/* Define the minimum DH group length we allow (unless the AllowWeakDH
+ * TLSOption is used). Ideally this would be 2048, per https://weakdh.org,
+ * but for compatibility with older Java versions, which only support up to
+ * 1024, we'll use 1024. For now.
+ */
+#define TLS_DH_MIN_LEN 1024
+
/* mod_tls session flags */
#define TLS_SESS_ON_CTRL 0x0001
#define TLS_SESS_ON_DATA 0x0002
@@ -438,6 +445,7 @@ static unsigned char *tls_authenticated = NULL;
#define TLS_OPT_USE_IMPLICIT_SSL 0x0200
#define TLS_OPT_ALLOW_CLIENT_RENEGOTIATIONS 0x0400
#define TLS_OPT_VERIFY_CERT_CN 0x0800
+#define TLS_OPT_ALLOW_WEAK_DH 0x1000
/* mod_tls SSCN modes */
#define TLS_SSCN_MODE_SERVER 0
@@ -2415,26 +2423,141 @@ static int tls_ctrl_renegotiate_cb(CALLBACK_FRAME) {
}
#endif
-static DH *tls_dh_cb(SSL *ssl, int is_export, int keylength) {
+static DH *tls_dh_cb(SSL *ssl, int is_export, int keylen) {
DH *dh = NULL;
+ EVP_PKEY *pkey;
+ int pkeylen = 0, use_pkeylen = FALSE;
+
+ /* OpenSSL will only ever call us (currently) with a keylen of 512 or 1024;
+ * see the SSL_EXPORT_PKEYLENGTH macro in ssl_locl.h. Sigh.
+ *
+ * Thus we adjust the DH parameter length according to the size of the
+ * RSA/DSA private key used for the current connection.
+ *
+ * NOTE: This MAY cause interoperability issues with some clients, notably
+ * Java 7 (and earlier) clients, since Java 7 and earlier supports
+ * Diffie-Hellman only up to 1024 bits. More sighs. To deal with these
+ * clients, then, you need to configure a certificate/key of 1024 bits.
+ */
+ pkey = SSL_get_privatekey(ssl);
+ if (pkey != NULL) {
+ if (EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA ||
+ EVP_PKEY_type(pkey->type) == EVP_PKEY_DSA) {
+ pkeylen = EVP_PKEY_bits(pkey);
+
+ if (pkeylen < TLS_DH_MIN_LEN) {
+ if (!(tls_opts & TLS_OPT_ALLOW_WEAK_DH)) {
+ pr_trace_msg(trace_channel, 11,
+ "certificate private key length %d less than %d bits, using %d "
+ "(see AllowWeakDH TLSOption)", pkeylen, TLS_DH_MIN_LEN,
+ TLS_DH_MIN_LEN);
+ pkeylen = TLS_DH_MIN_LEN;
+ }
+ }
+
+ if (pkeylen != keylen) {
+ pr_trace_msg(trace_channel, 13,
+ "adjusted DH parameter length from %d to %d bits", keylen, pkeylen);
+ use_pkeylen = TRUE;
+ }
+ }
+ }
if (tls_tmp_dhs != NULL &&
tls_tmp_dhs->nelts > 0) {
register unsigned int i;
- DH **dhs;
+ DH *best_dh = NULL, **dhs;
+ int best_dhlen = 0;
dhs = tls_tmp_dhs->elts;
+
+ /* Search the configured list of DH parameters twice: once for any sizes
+ * matching the actual requested size (usually 1024), and once for any
+ * matching the certificate private key size (pkeylen).
+ *
+ * This behavior allows site admins to configure a TLSDHParamFile that
+ * contains 1024-bit parameters, for e.g. Java 7 (and earlier) clients.
+ */
+
+ /* Note: the keylen argument is in BITS, but DH_size() returns the number
+ * of BYTES.
+ */
for (i = 0; i < tls_tmp_dhs->nelts; i++) {
- /* Note: the keylength argument is in BITS, but DH_size() returns
- * the number of BYTES.
+ int dhlen;
+
+ dhlen = DH_size(dhs[i]) * 8;
+ if (dhlen == keylen) {
+ pr_trace_msg(trace_channel, 11,
+ "found matching DH parameter for key length %d", keylen);
+ return dhs[i];
+ }
+
+ /* Try to find the next "best" DH to use, where "best" means
+ * the smallest DH that is larger than the necessary keylen.
*/
- if (DH_size(dhs[i]) == (keylength / 8)) {
+ if (dhlen > keylen) {
+ if (best_dh != NULL) {
+ if (dhlen < best_dhlen) {
+ best_dh = dhs[i];
+ best_dhlen = dhlen;
+ }
+
+ } else {
+ best_dh = dhs[i];
+ best_dhlen = dhlen;
+ }
+ }
+ }
+
+ for (i = 0; i < tls_tmp_dhs->nelts; i++) {
+ int dhlen;
+
+ dhlen = DH_size(dhs[i]) * 8;
+ if (dhlen == pkeylen) {
+ pr_trace_msg(trace_channel, 11,
+ "found matching DH parameter for certificate private key length %d",
+ pkeylen);
return dhs[i];
}
+
+ if (dhlen > pkeylen) {
+ if (best_dh != NULL) {
+ if (dhlen < best_dhlen) {
+ best_dh = dhs[i];
+ best_dhlen = dhlen;
+ }
+
+ } else {
+ best_dh = dhs[i];
+ best_dhlen = dhlen;
+ }
+ }
+ }
+
+ if (best_dh != NULL) {
+ pr_trace_msg(trace_channel, 11,
+ "using best DH parameter for key length %d (length %d)", keylen,
+ best_dhlen);
+ return best_dh;
}
}
- switch (keylength) {
+ /* Still no DH parameters found? Use the built-in ones. */
+
+ if (keylen < TLS_DH_MIN_LEN) {
+ if (!(tls_opts & TLS_OPT_ALLOW_WEAK_DH)) {
+ pr_trace_msg(trace_channel, 11,
+ "requested key length %d less than %d bits, using %d "
+ "(see AllowWeakDH TLSOption)", keylen, TLS_DH_MIN_LEN, TLS_DH_MIN_LEN);
+ keylen = TLS_DH_MIN_LEN;
+ }
+ }
+
+ if (use_pkeylen) {
+ keylen = pkeylen;
+ }
+
+ switch (keylen) {
case 512:
dh = get_dh512();
break;
@@ -2443,37 +2566,38 @@ static DH *tls_dh_cb(SSL *ssl, int is_export, int keylength) {
dh = get_dh768();
break;
- case 1024:
- dh = get_dh1024();
- break;
+ case 1024:
+ dh = get_dh1024();
+ break;
- case 1536:
- dh = get_dh1536();
- break;
+ case 1536:
+ dh = get_dh1536();
+ break;
- case 2048:
- dh = get_dh2048();
- break;
+ case 2048:
+ dh = get_dh2048();
+ break;
- default:
- tls_log("unsupported DH key length %d requested, returning 1024 bits",
- keylength);
- dh = get_dh1024();
- break;
+ default:
+ tls_log("unsupported DH key length %d requested, returning 1024 bits",
+ keylen);
+ dh = get_dh1024();
+ break;
}
+ pr_trace_msg(trace_channel, 11, "using builtin DH for %d bits", keylen);
+
/* Add this DH to the list, so that it can be freed properly later. */
if (tls_tmp_dhs == NULL) {
tls_tmp_dhs = make_array(session.pool, 1, sizeof(DH *));
}
*((DH **) push_array(tls_tmp_dhs)) = dh;
-
return dh;
}
#ifdef PR_USE_OPENSSL_ECC
-static EC_KEY *tls_ecdh_cb(SSL *ssl, int is_export, int keylength) {
+static EC_KEY *tls_ecdh_cb(SSL *ssl, int is_export, int keylen) {
static EC_KEY *ecdh = NULL;
static int init = 0;
@@ -4940,7 +5064,7 @@ static ssize_t tls_read(SSL *ssl, void *buf, size_t len) {
return count;
}
-static RSA *tls_rsa_cb(SSL *ssl, int is_export, int keylength) {
+static RSA *tls_rsa_cb(SSL *ssl, int is_export, int keylen) {
BIGNUM *e = NULL;
if (tls_tmp_rsa) {
@@ -4958,13 +5082,13 @@ static RSA *tls_rsa_cb(SSL *ssl, int is_export, int keylength) {
return NULL;
}
- if (RSA_generate_key_ex(tls_tmp_rsa, keylength, e, NULL) != 1) {
+ if (RSA_generate_key_ex(tls_tmp_rsa, keylen, e, NULL) != 1) {
BN_free(e);
return NULL;
}
#else
- tls_tmp_rsa = RSA_generate_key(keylength, RSA_F4, NULL, NULL);
+ tls_tmp_rsa = RSA_generate_key(keylen, RSA_F4, NULL, NULL);
#endif /* OpenSSL version 0.9.8 and later */
if (e != NULL) {
@@ -8445,6 +8569,9 @@ MODRET set_tlsoptions(cmd_rec *cmd) {
strcmp(cmd->argv[i], "AllowClientRenegotiations") == 0) {
opts |= TLS_OPT_ALLOW_CLIENT_RENEGOTIATIONS;
+ } else if (strcmp(cmd->argv[i], "AllowWeakDH") == 0) {
+ opts |= TLS_OPT_ALLOW_WEAK_DH;
+
} else if (strcmp(cmd->argv[i], "EnableDiags") == 0) {
opts |= TLS_OPT_ENABLE_DIAGS;
@@ -10051,7 +10178,7 @@ static conftable tls_conftab[] = {
static cmdtable tls_cmdtab[] = {
{ PRE_CMD, C_ANY, G_NONE, tls_any, FALSE, FALSE },
{ CMD, C_AUTH, G_NONE, tls_auth, FALSE, FALSE, CL_SEC },
- { CMD, C_CCC, G_NONE, tls_ccc, FALSE, FALSE, CL_SEC },
+ { CMD, C_CCC, G_NONE, tls_ccc, TRUE, FALSE, CL_SEC },
{ CMD, C_PBSZ, G_NONE, tls_pbsz, FALSE, FALSE, CL_SEC },
{ CMD, C_PROT, G_NONE, tls_prot, FALSE, FALSE, CL_SEC },
{ CMD, "SSCN", G_NONE, tls_sscn, TRUE, FALSE, CL_SEC },
diff --git a/include/version.h b/include/version.h
index e6ff92c..4a27172 100644
--- a/include/version.h
+++ b/include/version.h
@@ -1,8 +1,8 @@
#include "buildstamp.h"
/* Application version (in various forms) */
-#define PROFTPD_VERSION_NUMBER 0x0001030507
-#define PROFTPD_VERSION_TEXT "1.3.5a"
+#define PROFTPD_VERSION_NUMBER 0x0001030508
+#define PROFTPD_VERSION_TEXT "1.3.5b"
/* Module API version */
#define PR_MODULE_API_VERSION 0x20
diff --git a/lib/Makefile.in b/lib/Makefile.in
index f476488..8667ffe 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -39,8 +39,8 @@ clean:
test -z $(LIB_DEPS) || (cd libltdl/ && $(MAKE) clean)
depend:
- makedepend $(CPPFLAGS) -Y *.c 2>/dev/null
- makedepend $(CPPFLAGS) -Y -fMakefile.in *.c 2>/dev/null
+ $(MAKEDEPEND) $(CPPFLAGS) *.c 2>/dev/null
+ $(MAKEDEPEND) $(CPPFLAGS) -fMakefile.in *.c 2>/dev/null
distclean:
test -z $(LIB_DEPS) || (cd libltdl/ && $(MAKE) distclean)
diff --git a/lib/tpl.c b/lib/tpl.c
index a354c8f..5d10abf 100755
--- a/lib/tpl.c
+++ b/lib/tpl.c
@@ -23,9 +23,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define TPL_VERSION 1.5
-static const char id[]="$Id: tpl.c,v 1.4 2012-06-18 16:48:30 castaglia Exp $";
-
-
#include <stdlib.h> /* malloc */
#include <stdarg.h> /* va_list */
#include <string.h> /* memcpy, memset, strchr */
@@ -229,7 +226,6 @@ tpl_hook_t tpl_hook = {
};
static const char tpl_fmt_chars[] = "AS($)BiucsfIUjv#"; /* valid format chars */
-static const char tpl_S_fmt_chars[] = "iucsfIUjv#$()"; /* valid within S(...) */
static const char tpl_datapeek_ok_chars[] = "iucsfIUjv"; /* valid in datapeek */
static const struct tpl_type_t tpl_types[] = {
/* [TPL_TYPE_ROOT] = */ {'r', 0},
diff --git a/modules/Makefile.in b/modules/Makefile.in
index 7057eb1..11e8971 100644
--- a/modules/Makefile.in
+++ b/modules/Makefile.in
@@ -69,5 +69,5 @@ clean:
depend:
$(RM) module_glue.c
- makedepend $(CPPFLAGS) -Y *.c 2>/dev/null
- makedepend $(CPPFLAGS) -Y -fMakefile.in *.c 2>/dev/null
+ $(MAKEDEPEND) $(CPPFLAGS) *.c 2>/dev/null
+ $(MAKEDEPEND) $(CPPFLAGS) -fMakefile.in *.c 2>/dev/null
diff --git a/modules/mod_auth.c b/modules/mod_auth.c
index faadf83..abe6ff8 100644
--- a/modules/mod_auth.c
+++ b/modules/mod_auth.c
@@ -2,7 +2,7 @@
* ProFTPD - FTP server daemon
* Copyright (c) 1997, 1998 Public Flood Software
* Copyright (c) 1999, 2000 MacGyver aka Habeeb J. Dihu <macgyver at tos.net>
- * Copyright (c) 2001-2014 The ProFTPD Project team
+ * Copyright (c) 2001-2016 The ProFTPD Project team
*
* 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
@@ -24,9 +24,7 @@
* the source code for OpenSSL in the source distribution.
*/
-/* Authentication module for ProFTPD
- * $Id: mod_auth.c,v 1.317 2013-12-29 20:17:09 castaglia Exp $
- */
+/* Authentication module for ProFTPD */
#include "conf.h"
#include "privs.h"
@@ -591,7 +589,7 @@ MODRET auth_post_pass(cmd_rec *cmd) {
*/
if (session.c->local_port < 1024) {
pr_log_debug(DEBUG0,
- "RootRevoke in effect, disabling active transfers");
+ "RootRevoke in effect, active data transfers may not succeed");
}
}
@@ -2168,11 +2166,25 @@ MODRET auth_user(cmd_rec *cmd) {
int failnopwprompt = 0, aclp, i;
unsigned char *anon_require_passwd = NULL, *login_passwd_prompt = NULL;
- if (logged_in)
- return PR_ERROR_MSG(cmd, R_500, _("Bad sequence of commands"));
-
- if (cmd->argc < 2)
+ if (cmd->argc < 2) {
return PR_ERROR_MSG(cmd, R_500, _("USER: command requires a parameter"));
+ }
+
+ if (logged_in) {
+ /* If the client has already authenticated, BUT the given USER command
+ * here is for the exact same user name, then allow the command to
+ * succeed (Bug#4217).
+ */
+ origuser = pr_table_get(session.notes, "mod_auth.orig-user", NULL);
+ if (origuser != NULL &&
+ strcmp(origuser, cmd->arg) == 0) {
+ pr_response_add(R_230, _("User %s logged in"), origuser);
+ return PR_HANDLED(cmd);
+ }
+
+ pr_response_add_err(R_501, "%s", _("Reauthentication not supported"));
+ return PR_ERROR(cmd);
+ }
user = cmd->arg;
@@ -2292,10 +2304,10 @@ MODRET auth_user(cmd_rec *cmd) {
pr_response_add(R_331, _("Anonymous login ok, send your complete email "
"address as your password"));
- /* Check to see if a password from the client is required. In the
- * vast majority of cases, a password will be required.
- */
} else if (pr_auth_requires_pass(cmd->tmp_pool, user) == FALSE) {
+ /* Check to see if a password from the client is required. In the
+ * vast majority of cases, a password will be required.
+ */
/* Act as if we received a PASS command from the client. */
cmd_rec *fakecmd = pr_cmd_alloc(cmd->pool, 2, NULL);
diff --git a/modules/mod_core.c b/modules/mod_core.c
index 7659630..080a97c 100644
--- a/modules/mod_core.c
+++ b/modules/mod_core.c
@@ -3569,7 +3569,7 @@ MODRET core_port(cmd_rec *cmd) {
*root_revoke == 1 &&
session.c->local_port < 1024) {
pr_log_debug(DEBUG0, "RootRevoke in effect, unable to bind to local "
- "port %d for active transfer", session.c->local_port);
+ "port %d for active transfer", session.c->local_port-1);
pr_response_add_err(R_500, _("Unable to service PORT commands"));
errno = EPERM;
return PR_ERROR(cmd);
@@ -3773,7 +3773,7 @@ MODRET core_eprt(cmd_rec *cmd) {
*root_revoke == 1 &&
session.c->local_port < 1024) {
pr_log_debug(DEBUG0, "RootRevoke in effect, unable to bind to local "
- "port %d for active transfer", session.c->local_port);
+ "port %d for active transfer", session.c->local_port-1);
pr_response_add_err(R_500, _("Unable to service EPRT commands"));
errno = EPERM;
return PR_ERROR(cmd);
diff --git a/modules/mod_facts.c b/modules/mod_facts.c
index 7291f4d..09f8e2e 100644
--- a/modules/mod_facts.c
+++ b/modules/mod_facts.c
@@ -1,7 +1,7 @@
/*
* ProFTPD: mod_facts -- a module for handling "facts" [RFC3659]
*
- * Copyright (c) 2007-2013 The ProFTPD Project
+ * Copyright (c) 2007-2015 The ProFTPD Project
*
* 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
@@ -21,14 +21,12 @@
* give permission to link this program with OpenSSL, and distribute the
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
- *
- * $Id: mod_facts.c,v 1.60 2013-04-16 16:04:43 castaglia Exp $
*/
#include "conf.h"
#include "privs.h"
-#define MOD_FACTS_VERSION "mod_facts/0.3"
+#define MOD_FACTS_VERSION "mod_facts/0.4"
#if PROFTPD_VERSION_NUMBER < 0x0001030101
# error "ProFTPD 1.3.1rc1 or later required"
@@ -49,6 +47,8 @@ static unsigned long facts_opts = 0;
static unsigned long facts_mlinfo_opts = 0;
#define FACTS_MLINFO_FL_SHOW_SYMLINKS 0x00001
#define FACTS_MLINFO_FL_SHOW_SYMLINKS_USE_SLINK 0x00002
+#define FACTS_MLINFO_FL_NO_CDIR 0x00004
+#define FACTS_MLINFO_FL_APPEND_CRLF 0x00008
struct mlinfo {
pool *pool;
@@ -203,7 +203,8 @@ static time_t facts_mktime(unsigned int year, unsigned int month,
return res;
}
-static size_t facts_mlinfo_fmt(struct mlinfo *info, char *buf, size_t bufsz) {
+static size_t facts_mlinfo_fmt(struct mlinfo *info, char *buf, size_t bufsz,
+ int flags) {
char *ptr;
size_t buflen = 0;
@@ -267,13 +268,8 @@ static size_t facts_mlinfo_fmt(struct mlinfo *info, char *buf, size_t bufsz) {
ptr = buf + buflen;
}
- /* MLST entries are not sent via pr_data_xfer(), and thus we do not need
- * to include an LF at the end; it is appended by pr_response_send_raw().
- * But MLSD entries DO need the trailing LF, so that it can be converted
- * into a CRLF sequence by pr_data_xfer().
- */
- if (strcmp(session.curr_cmd, C_MLSD) == 0) {
- snprintf(ptr, bufsz - buflen, " %s\n", info->path);
+ if (flags & FACTS_MLINFO_FL_APPEND_CRLF) {
+ snprintf(ptr, bufsz - buflen, " %s\r\n", info->path);
} else {
snprintf(ptr, bufsz - buflen, " %s", info->path);
@@ -311,11 +307,11 @@ static void facts_mlinfobuf_init(void) {
mlinfo_buflen = 0;
}
-static void facts_mlinfobuf_add(struct mlinfo *info) {
+static void facts_mlinfobuf_add(struct mlinfo *info, int flags) {
char buf[PR_TUNABLE_BUFFER_SIZE];
size_t buflen;
- buflen = facts_mlinfo_fmt(info, buf, sizeof(buf));
+ buflen = facts_mlinfo_fmt(info, buf, sizeof(buf), flags);
/* If this buffer will exceed the capacity of mlinfo_buf, then flush
* mlinfo_buf.
@@ -491,20 +487,17 @@ static int facts_mlinfo_get(struct mlinfo *info, const char *path,
} else {
info->type = "dir";
- if (dent_name[0] != '.') {
- if (strcmp(path, pr_fs_getcwd()) == 0) {
- info->type = "cdir";
- }
-
- } else {
- if (dent_name[1] == '\0') {
- info->type = "cdir";
- }
+ if (!(flags & FACTS_MLINFO_FL_NO_CDIR)) {
+ if (dent_name[0] == '.') {
+ if (dent_name[1] == '\0') {
+ info->type = "cdir";
+ }
- if (strlen(dent_name) >= 2) {
- if (dent_name[1] == '.' &&
- dent_name[2] == '\0') {
- info->type = "pdir";
+ if (strlen(dent_name) >= 2) {
+ if (dent_name[1] == '.' &&
+ dent_name[2] == '\0') {
+ info->type = "pdir";
+ }
}
}
}
@@ -538,10 +531,10 @@ static int facts_mlinfo_get(struct mlinfo *info, const char *path,
return 0;
}
-static void facts_mlinfo_add(struct mlinfo *info) {
+static void facts_mlinfo_add(struct mlinfo *info, int flags) {
char buf[PR_TUNABLE_BUFFER_SIZE];
- (void) facts_mlinfo_fmt(info, buf, sizeof(buf));
+ (void) facts_mlinfo_fmt(info, buf, sizeof(buf), flags);
/* The trailing CRLF will be added by pr_response_add(). */
pr_response_add(R_DUP, "%s", buf);
@@ -1239,7 +1232,14 @@ MODRET facts_mlsd(cmd_rec *cmd) {
/* Open data connection */
if (pr_data_open(NULL, C_MLSD, PR_NETIO_IO_WR, 0) < 0) {
+ int xerrno = errno;
+
pr_fsio_closedir(dirh);
+
+ pr_response_add_err(R_550, "%s: %s", (char *) cmd->argv[0],
+ strerror(xerrno));
+
+ errno = xerrno;
return PR_ERROR(cmd);
}
session.sf_flags |= SF_ASCII_OVERRIDE;
@@ -1292,7 +1292,7 @@ MODRET facts_mlsd(cmd_rec *cmd) {
*/
info.path = pr_fs_encode_path(cmd->tmp_pool, dent->d_name);
- facts_mlinfobuf_add(&info);
+ facts_mlinfobuf_add(&info, FACTS_MLINFO_FL_APPEND_CRLF);
if (XFER_ABORTED) {
pr_data_abort(0, 0);
@@ -1425,6 +1425,13 @@ MODRET facts_mlst(cmd_rec *cmd) {
info.pool = cmd->tmp_pool;
+ /* Since this is an MLST command, we are not listing the contents of
+ * of a directory, we're only showing the entry for a path, whether
+ * directory or not. Thus the "cdir" type fact should not be used
+ * (Bug#4198).
+ */
+ flags |= FACTS_MLINFO_FL_NO_CDIR;
+
pr_fs_clear_cache();
if (facts_mlinfo_get(&info, decoded_path, decoded_path, flags, fake_uid,
fake_gid, fake_mode) < 0) {
@@ -1458,7 +1465,7 @@ MODRET facts_mlst(cmd_rec *cmd) {
}
pr_response_add(R_250, _("Start of list for %s"), path);
- facts_mlinfo_add(&info);
+ facts_mlinfo_add(&info, 0);
pr_response_add(R_250, _("End of list"));
return PR_HANDLED(cmd);
diff --git a/modules/mod_log.c b/modules/mod_log.c
index 38f2cd1..5200b40 100644
--- a/modules/mod_log.c
+++ b/modules/mod_log.c
@@ -2,7 +2,7 @@
* ProFTPD - FTP server daemon
* Copyright (c) 1997, 1998 Public Flood Software
* Copyright (c) 1999, 2000 MacGyver aka Habeeb J. Dihu <macgyver at tos.net>
- * Copyright (c) 2001-2013 The ProFTPD Project team
+ * Copyright (c) 2001-2015 The ProFTPD Project team
*
* 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
@@ -24,9 +24,7 @@
* the source code for OpenSSL in the source distribution.
*/
-/* Flexible logging module for proftpd
- * $Id: mod_log.c,v 1.155 2013-11-11 01:34:04 castaglia Exp $
- */
+/* Flexible logging module for proftpd */
#include "conf.h"
#include "privs.h"
@@ -38,6 +36,7 @@ module log_module;
#define EXTENDED_LOG_BUFFER_SIZE (PR_TUNABLE_PATH_MAX + 128)
#define EXTENDED_LOG_MODE 0644
+#define EXTENDED_LOG_FORMAT_DEFAULT "default"
typedef struct logformat_struc logformat_t;
typedef struct logfile_struc logfile_t;
@@ -433,8 +432,9 @@ static void logformat(const char *directive, char *nickname, char *fmts) {
lf->lf_format = palloc(log_pool, outs - format);
memcpy(lf->lf_format, format, outs - format);
- if (!format_set)
+ if (format_set == NULL) {
format_set = xaset_create(log_pool, NULL);
+ }
xaset_insert_end(format_set, (xasetmember_t *) lf);
formats = (logformat_t *) format_set->xas_list;
@@ -1721,8 +1721,9 @@ MODRET log_any(cmd_rec *cmd) {
if (!session.anon_config &&
lf->lf_conf &&
- lf->lf_conf->config_type == CONF_ANON)
+ lf->lf_conf->config_type == CONF_ANON) {
continue;
+ }
do_log(cmd, lf);
}
@@ -1892,6 +1893,19 @@ static void find_extendedlogs(void) {
}
if (logfmt == NULL) {
+ if (strcasecmp(logfmt_s, EXTENDED_LOG_FORMAT_DEFAULT) == 0) {
+ /* Try again, this time looking for the default LogFormat
+ * name, which is registered using a nickname of "".
+ */
+ for (logfmt = formats; logfmt; logfmt = logfmt->next) {
+ if (strcmp(logfmt->lf_nickname, "") == 0) {
+ break;
+ }
+ }
+ }
+ }
+
+ if (logfmt == NULL) {
pr_log_pri(PR_LOG_NOTICE,
"ExtendedLog '%s' uses unknown format nickname '%s'", logfname,
logfmt_s);
diff --git a/modules/mod_ls.c b/modules/mod_ls.c
index e55f1e4..e9a9049 100644
--- a/modules/mod_ls.c
+++ b/modules/mod_ls.c
@@ -1816,6 +1816,12 @@ static int dolist(cmd_rec *cmd, const char *opt, int clearflags) {
/* Open data connection */
if (!opt_STAT) {
if (pr_data_open(NULL, "file list", PR_NETIO_IO_WR, 0) < 0) {
+ int xerrno = errno;
+
+ pr_response_add_err(R_450, "%s: %s", (char *) cmd->argv[0],
+ strerror(xerrno));
+
+ errno = xerrno;
return -1;
}
@@ -2044,6 +2050,12 @@ static int dolist(cmd_rec *cmd, const char *opt, int clearflags) {
/* Open data connection */
if (!opt_STAT) {
if (pr_data_open(NULL, "file list", PR_NETIO_IO_WR, 0) < 0) {
+ int xerrno = errno;
+
+ pr_response_add_err(R_450, "%s: %s", (char *) cmd->argv[0],
+ strerror(xerrno));
+
+ errno = xerrno;
return -1;
}
@@ -2826,6 +2838,12 @@ MODRET ls_nlst(cmd_rec *cmd) {
} else {
if (list_flags & LS_FL_NO_ERROR_IF_ABSENT) {
if (pr_data_open(NULL, "file list", PR_NETIO_IO_WR, 0) < 0) {
+ int xerrno = errno;
+
+ pr_response_add_err(R_450, "%s: %s", (char *) cmd->argv[0],
+ strerror(xerrno));
+
+ errno = xerrno;
return PR_ERROR(cmd);
}
@@ -2843,6 +2861,12 @@ MODRET ls_nlst(cmd_rec *cmd) {
} else {
if (list_flags & LS_FL_NO_ERROR_IF_ABSENT) {
if (pr_data_open(NULL, "file list", PR_NETIO_IO_WR, 0) < 0) {
+ int xerrno = errno;
+
+ pr_response_add_err(R_450, "%s: %s", (char *) cmd->argv[0],
+ strerror(xerrno));
+
+ errno = xerrno;
return PR_ERROR(cmd);
}
@@ -2859,6 +2883,12 @@ MODRET ls_nlst(cmd_rec *cmd) {
}
if (pr_data_open(NULL, "file list", PR_NETIO_IO_WR, 0) < 0) {
+ int xerrno = errno;
+
+ pr_response_add_err(R_450, "%s: %s", (char *) cmd->argv[0],
+ strerror(xerrno));
+
+ errno = xerrno;
return PR_ERROR(cmd);
}
@@ -2935,6 +2965,12 @@ MODRET ls_nlst(cmd_rec *cmd) {
if (xerrno == ENOENT &&
(list_flags & LS_FL_NO_ERROR_IF_ABSENT)) {
if (pr_data_open(NULL, "file list", PR_NETIO_IO_WR, 0) < 0) {
+ xerrno = errno;
+
+ pr_response_add_err(R_450, "%s: %s", (char *) cmd->argv[0],
+ strerror(xerrno));
+
+ errno = xerrno;
return PR_ERROR(cmd);
}
session.sf_flags |= SF_ASCII_OVERRIDE;
@@ -2964,6 +3000,12 @@ MODRET ls_nlst(cmd_rec *cmd) {
if (list_flags & LS_FL_NO_ERROR_IF_ABSENT) {
if (pr_data_open(NULL, "file list", PR_NETIO_IO_WR, 0) < 0) {
+ int xerrno = errno;
+
+ pr_response_add_err(R_450, "%s: %s", (char *) cmd->argv[0],
+ strerror(xerrno));
+
+ errno = xerrno;
return PR_ERROR(cmd);
}
session.sf_flags |= SF_ASCII_OVERRIDE;
@@ -2995,6 +3037,12 @@ MODRET ls_nlst(cmd_rec *cmd) {
if (xerrno == ENOENT &&
(list_flags & LS_FL_NO_ERROR_IF_ABSENT)) {
if (pr_data_open(NULL, "file list", PR_NETIO_IO_WR, 0) < 0) {
+ xerrno = errno;
+
+ pr_response_add_err(R_450, "%s: %s", (char *) cmd->argv[0],
+ strerror(xerrno));
+
+ errno = xerrno;
return PR_ERROR(cmd);
}
session.sf_flags |= SF_ASCII_OVERRIDE;
@@ -3012,6 +3060,12 @@ MODRET ls_nlst(cmd_rec *cmd) {
if (S_ISREG(st.st_mode)) {
if (pr_data_open(NULL, "file list", PR_NETIO_IO_WR, 0) < 0) {
+ int xerrno = errno;
+
+ pr_response_add_err(R_450, "%s: %s", (char *) cmd->argv[0],
+ strerror(xerrno));
+
+ errno = xerrno;
return PR_ERROR(cmd);
}
session.sf_flags |= SF_ASCII_OVERRIDE;
diff --git a/modules/mod_xfer.c b/modules/mod_xfer.c
index f09046d..6e1b2a2 100644
--- a/modules/mod_xfer.c
+++ b/modules/mod_xfer.c
@@ -2,7 +2,7 @@
* ProFTPD - FTP server daemon
* Copyright (c) 1997, 1998 Public Flood Software
* Copyright (c) 1999, 2000 MacGyver aka Habeeb J. Dihu <macgyver at tos.net>
- * Copyright (c) 2001-2015 The ProFTPD Project team
+ * Copyright (c) 2001-2016 The ProFTPD Project team
*
* 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
@@ -1351,7 +1351,7 @@ MODRET xfer_pre_stor(cmd_rec *cmd) {
MODRET xfer_pre_stou(cmd_rec *cmd) {
config_rec *c = NULL;
char *prefix = "ftp", *filename = NULL;
- int tmpfd;
+ int stou_fd;
mode_t mode;
unsigned char *allow_overwrite = NULL;
@@ -1386,16 +1386,17 @@ MODRET xfer_pre_stou(cmd_rec *cmd) {
* unique filename prefix.
*/
c = find_config(CURRENT_CONF, CONF_PARAM, "StoreUniquePrefix", FALSE);
- if (c != NULL)
+ if (c != NULL) {
prefix = c->argv[0];
+ }
/* Now, construct the unique filename using the cmd_rec's pool, the
* prefix, and mkstemp().
*/
filename = pstrcat(cmd->pool, prefix, "XXXXXX", NULL);
- tmpfd = mkstemp(filename);
- if (tmpfd < 0) {
+ stou_fd = mkstemp(filename);
+ if (stou_fd < 0) {
int xerrno = errno;
pr_log_pri(PR_LOG_WARNING, "error: unable to use mkstemp(): %s",
@@ -1416,13 +1417,13 @@ MODRET xfer_pre_stou(cmd_rec *cmd) {
* opens the unique file, but this may have to do, as closing that
* race would involve some major restructuring.
*/
- close(tmpfd);
+ (void) close(stou_fd);
}
/* It's OK to reuse the char * pointer for filename. */
filename = dir_best_path(cmd->tmp_pool, cmd->arg);
- if (!filename ||
+ if (filename == NULL ||
!dir_check(cmd->tmp_pool, cmd, cmd->group, filename, NULL)) {
int xerrno = errno;
@@ -1477,22 +1478,30 @@ MODRET xfer_pre_stou(cmd_rec *cmd) {
}
/* xfer_post_stou() is a POST_CMD handler that changes the mode of the
- * STOU file from 0600, which is what mkstemp() makes it, to 0666,
- * the default for files uploaded via STOR. This is to prevent users
+ * STOU file from 0600, which is what mkstemp() makes it, to 0666 (modulo
+ * Umask), the default for files uploaded via STOR. This is to prevent users
* from being surprised.
*/
MODRET xfer_post_stou(cmd_rec *cmd) {
+ mode_t mask, perms, *umask;
- /* This is the same mode as used in src/fs.c. Should probably be
- * available as a macro.
+ /* mkstemp(3) creates a file with 0600 perms; we need to adjust this
+ * for the Umask (Bug#4223).
*/
- mode_t mode = 0666;
+ umask = get_param_ptr(CURRENT_CONF, "Umask", FALSE);
+ if (umask != NULL) {
+ mask = *umask;
+
+ } else {
+ mask = (mode_t) 0022;
+ }
- if (pr_fsio_chmod(cmd->arg, mode) < 0) {
+ perms = (0666 & ~mask);
+ if (pr_fsio_chmod(cmd->arg, perms) < 0) {
/* Not much to do but log the error. */
pr_log_pri(PR_LOG_NOTICE, "error: unable to chmod '%s' to %04o: %s",
- cmd->arg, mode, strerror(errno));
+ cmd->arg, perms, strerror(errno));
}
return PR_DECLINED(cmd);
diff --git a/src/Makefile.in b/src/Makefile.in
index c9e4702..3a42ccb 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -25,5 +25,5 @@ clean:
rm -f *.o
depend:
- makedepend $(CPPFLAGS) -Y *.c 2>/dev/null
- makedepend $(CPPFLAGS) -Y -fMakefile.in *.c 2>/dev/null
+ $(MAKEDEPEND) $(CPPFLAGS) *.c 2>/dev/null
+ $(MAKEDEPEND) $(CPPFLAGS) -fMakefile.in *.c 2>/dev/null
diff --git a/src/data.c b/src/data.c
index 5da377b..5136f5f 100644
--- a/src/data.c
+++ b/src/data.c
@@ -358,14 +358,30 @@ static int data_active_open(char *reason, off_t size) {
*/
bind_port = session.c->local_port-1;
- /* A RootRevoke value of 0 indicates 'false', 1 indicates 'true', and
- * 2 indicates 'NonCompliantActiveTransfer'. We change the source port for
- * a RootRevoke value of 2.
- */
root_revoke = get_param_ptr(TOPLEVEL_CONF, "RootRevoke", FALSE);
- if (root_revoke != NULL &&
- *root_revoke == 2) {
- bind_port = INPORT_ANY;
+ if (root_revoke != NULL) {
+ /* A RootRevoke value of 0 indicates 'false', 1 indicates 'true', and
+ * 2 indicates 'NonCompliantActiveTransfer'. We change the source port for
+ * a RootRevoke value of 2, and for a value of 1, we make sure that
+ * that the port is not a privileged port.
+ */
+ switch (*root_revoke) {
+ case 1:
+ if (bind_port < 1024) {
+ pr_log_debug(DEBUG0, "RootRevoke in effect, unable to bind to local "
+ "port %d for active transfer", bind_port);
+ errno = EPERM;
+ return -1;
+ }
+ break;
+
+ case 2:
+ bind_port = INPORT_ANY;
+ break;
+
+ default:
+ break;
+ }
}
session.d = pr_inet_create_conn(session.pool, -1, bind_addr, bind_port, TRUE);
diff --git a/src/encode.c b/src/encode.c
index dd4bf79..b2ceeae 100644
--- a/src/encode.c
+++ b/src/encode.c
@@ -1,6 +1,6 @@
/*
* ProFTPD - FTP server daemon
- * Copyright (c) 2006-2012 The ProFTPD Project team
+ * Copyright (c) 2006-2015 The ProFTPD Project team
*
* 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
@@ -22,9 +22,7 @@
* OpenSSL in the source distribution.
*/
-/* UTF8/charset encoding/decoding
- * $Id: encode.c,v 1.33 2012-04-06 16:44:40 castaglia Exp $
- */
+/* UTF8/charset encoding/decoding */
#include "conf.h"
@@ -65,7 +63,7 @@ static int str_convert(iconv_t conv, const char *inbuf, size_t *inbuflen,
*/
#if defined(LINUX) || defined(DARWIN6) || defined(DARWIN7) || \
defined(DARWIN8) || defined(DARWIN9) || defined(DARWIN10) || \
- defined(DARWIN11)
+ defined(DARWIN11) || defined(DARWIN12)
nconv = iconv(conv, (char **) &inbuf, inbuflen, &outbuf, outbuflen);
#else
diff --git a/src/fsio.c b/src/fsio.c
index 333a17f..f088202 100644
--- a/src/fsio.c
+++ b/src/fsio.c
@@ -1717,6 +1717,30 @@ int pr_fs_dircat(char *buf, int buflen, const char *dir1, const char *dir2) {
dir1len = strlen(dir1);
dir2len = strlen(dir2);
+ /* If both strings are empty, then the "concatenation" becomes trivial. */
+ if (dir1len == 0 &&
+ dir2len == 0) {
+ buf[0] = '/';
+ buf[1] = '\0';
+ return 0;
+ }
+
+ /* If dir2 is non-empty, but dir1 IS empty... */
+ if (dir1len == 0) {
+ sstrncpy(buf, dir2, buflen);
+ buflen -= dir2len;
+ sstrcat(buf, "/", buflen);
+ return 0;
+ }
+
+ /* Likewise, if dir1 is non-empty, but dir2 IS empty... */
+ if (dir2len == 0) {
+ sstrncpy(buf, dir1, buflen);
+ buflen -= dir1len;
+ sstrcat(buf, "/", buflen);
+ return 0;
+ }
+
if ((dir1len + dir2len + 1) >= PR_TUNABLE_PATH_MAX) {
errno = ENAMETOOLONG;
buf[0] = '\0';
@@ -1751,7 +1775,8 @@ int pr_fs_dircat(char *buf, int buflen, const char *dir1, const char *dir2) {
buflen -= dir1len;
if (buflen > 0 &&
- *(_dir1 + (dir1len-1)) != '/') {
+ dir1len >= 1 &&
+ *(_dir1 + (dir1len-1)) != '/') {
sstrcat(ptr, "/", buflen);
ptr += 1;
buflen -= 1;
diff --git a/src/ftpscrub.c b/src/ftpscrub.c
deleted file mode 100644
index e7dd8f3..0000000
--- a/src/ftpscrub.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * ProFTPD - FTP server daemon
- * Copyright (c) 2001-2008 The ProFTPD Project team
- *
- * 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.
- *
- * As a special exemption, The ProFTPD Project and other respective copyright
- * holders give permission to link this program with OpenSSL, and distribute
- * the resulting executable, without including the source code for OpenSSL in
- * the source distribution.
- */
-
-/* "Scrubs" the scoreboard file, clearing it of old/stale entries.
- * $Id: ftpscrub.c,v 1.1 2009-02-18 21:33:17 castaglia Exp $
- */
-
-#include "utils.h"
-
-static const char *config_filename = PR_CONFIG_FILE_PATH;
-
-static int check_scoreboard_file(void) {
- struct stat st;
-
- if (stat(util_get_scoreboard(), &st) < 0)
- return -1;
-
- return 0;
-}
-
-static struct option_help {
- const char *long_opt, *short_opt, *desc;
-} opts_help[] = {
- { "--config", "-c", "specify full path to proftpd configuration file" },
- { "--file", "-f", "specify full path to scoreboard file" },
- { "--help", "-h", NULL },
- { "--verbose","-v", NULL },
- { NULL }
-};
-
-#ifdef HAVE_GETOPT_LONG
-static struct option opts[] = {
- { "config", 1, NULL, 'c' },
- { "file", 1, NULL, 'f' },
- { "help", 0, NULL, 'h' },
- { "verbose", 0, NULL, 'v' },
- { NULL, 0, NULL, 0 }
-};
-#endif /* HAVE_GETOPT_LONG */
-
-static void show_usage(const char *progname, int exit_code) {
- struct option_help *h = NULL;
-
- printf("usage: %s [options]\n", progname);
- for (h = opts_help; h->long_opt; h++) {
-#ifdef HAVE_GETOPT_LONG
- printf(" %s, %s\n", h->short_opt, h->long_opt);
-#else /* HAVE_GETOPT_LONG */
- printf(" %s\n", h->short_opt);
-#endif
- if (!h->desc)
- printf(" display %s usage\n", progname);
- else
- printf(" %s\n", h->desc);
- }
-
- exit(exit_code);
-}
-
-int main(int argc, char **argv) {
- int c = 0, res = 0;
- int verbose = FALSE;
- char *cp, *progname = *argv;
- const char *cmdopts = "c:f:hv";
-
- cp = strrchr(progname, '/');
- if (cp != NULL)
- progname = cp+1;
-
- opterr = 0;
- while ((c =
-#ifdef HAVE_GETOPT_LONG
- getopt_long(argc, argv, cmdopts, opts, NULL)
-#else /* HAVE_GETOPT_LONG */
- getopt(argc, argv, cmdopts)
-#endif /* HAVE_GETOPT_LONG */
- ) != -1) {
- switch (c) {
- case 'h':
- show_usage(progname, 0);
-
- case 'f':
- util_set_scoreboard(optarg);
- break;
-
- case 'c':
- config_filename = strdup(optarg);
- break;
-
- case 'v':
- verbose = TRUE;
- break;
-
- case '?':
- fprintf(stderr, "unknown option: %c\n", (char) optopt);
- show_usage(progname, 1);
- }
- }
-
- /* First attempt to check the supplied/default scoreboard path. If this is
- * incorrect, try the config file kludge.
- */
- if (check_scoreboard_file() < 0) {
- const char *file = util_scan_config(config_filename, "ScoreboardFile");
- if (file)
- util_set_scoreboard(file);
-
- if (check_scoreboard_file() < 0) {
- fprintf(stderr, "%s: %s\n", util_get_scoreboard(), strerror(errno));
- fprintf(stderr, "(Perhaps you need to specify the ScoreboardFile with -f, or change\n");
- fprintf(stderr," the compile-time default directory?)\n");
- exit(1);
- }
- }
-
- res = util_scoreboard_scrub(verbose);
- if (res < 0) {
- fprintf(stderr, "error scrubbing scoreboard %s: %s\n",
- util_get_scoreboard(), strerror(errno));
- return 1;
- }
-
- return 0;
-}
diff --git a/src/inet.c b/src/inet.c
index 7676cd9..4a3e7df 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -236,6 +236,7 @@ static conn_t *init_conn(pool *p, int fd, pr_netaddr_t *bind_addr,
defined(__OpenBSD__) || defined(__NetBSD__) || \
defined(DARWIN6) || defined(DARWIN7) || defined(DARWIN8) || \
defined(DARWIN9) || defined(DARWIN10) || defined(DARWIN11) || \
+ defined(DARWIN12) || \
defined(SCO3) || defined(CYGWIN) || defined(SYSV4_2MP) || \
defined(SYSV5SCO_SV6) || defined(SYSV5UNIXWARE7)
# ifdef SOLARIS2
@@ -260,6 +261,7 @@ static conn_t *init_conn(pool *p, int fd, pr_netaddr_t *bind_addr,
defined(__OpenBSD__) || defined(__NetBSD__) || \
defined(DARWIN6) || defined(DARWIN7) || defined(DARWIN8) || \
defined(DARWIN9) || defined(DARWIN10) || defined(DARWIN11) || \
+ defined(DARWIN12) || \
defined(SCO3) || defined(CYGWIN) || defined(SYSV4_2MP) || \
defined(SYSV5SCO_SV6) || defined(SYSV5UNIXWARE7)
# ifdef SOLARIS2
diff --git a/src/main.c b/src/main.c
index 0945bc8..98f7526 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1530,14 +1530,20 @@ static void daemon_loop(void) {
}
running = 1;
+ xerrno = errno = 0;
PR_DEVEL_CLOCK(i = select(maxfd + 1, &listenfds, NULL, NULL, &tv));
if (i < 0) {
xerrno = errno;
}
- if (i == -1 && xerrno == EINTR) {
+ if (i == -1 &&
+ xerrno == EINTR) {
+ errno = xerrno;
pr_signals_handle();
+
+ /* We handled our signal; clear errno. */
+ xerrno = errno = 0;
continue;
}
@@ -1679,6 +1685,9 @@ void pr_signals_handle(void) {
(unsigned long) tv.tv_usec, tv.tv_usec != 1 ? "microsecs" : "microsec");
pr_timer_usleep(interval_usecs);
+
+ /* Clear the EINTR errno, now we've dealt with it. */
+ errno = 0;
}
while (recvd_signal_flags) {
diff --git a/src/pool.c b/src/pool.c
index 43b53c8..f620694 100644
--- a/src/pool.c
+++ b/src/pool.c
@@ -86,43 +86,37 @@ static void oom_printf(const char *fmt, ...) {
/* Lowest level memory allocation functions
*/
-static void *null_alloc(size_t size) {
- void *ret = NULL;
-
- if (size == 0) {
- /* Yes, this code is correct.
- *
- * The size argument is the originally requested amount of memory.
- * null_alloc() is called because smalloc() returned NULL. But why,
- * exactly? If the requested size is zero, then it may not have been
- * an error -- or it may be because the system is actually out of memory.
- * To differentiate, we do a malloc(0) call here if the requested size is
- * zero. If malloc(0) returns NULL, then we really do have an error.
- */
- ret = malloc(size);
- }
-
- if (ret == NULL) {
- pr_log_pri(PR_LOG_ALERT, "Out of memory!");
+static void null_alloc(void) {
+ pr_log_pri(PR_LOG_ALERT, "Out of memory!");
#ifdef PR_USE_DEVEL
- if (debug_flags & PR_POOL_DEBUG_FL_OOM_DUMP_POOLS) {
- pr_pool_debug_memory(oom_printf);
- }
-#endif
- exit(1);
+ if (debug_flags & PR_POOL_DEBUG_FL_OOM_DUMP_POOLS) {
+ pr_pool_debug_memory(oom_printf);
}
+#endif
- return ret;
+ exit(1);
}
static void *smalloc(size_t size) {
- void *ret;
+ void *res;
- ret = malloc(size);
- if (ret == 0)
- ret = null_alloc(size);
+ if (size == 0) {
+ /* Avoid zero-length malloc(); on non-POSIX systems, the behavior is
+ * not dependable. And on POSIX systems, malloc(3) might still return
+ * a "unique pointer" for a zero-length allocation (or NULL).
+ *
+ * Either way, a zero-length allocation request here means that someone
+ * is doing something they should not be doing.
+ */
+ null_alloc();
+ }
+
+ res = malloc(size);
+ if (res == NULL) {
+ null_alloc();
+ }
- return ret;
+ return res;
}
/* Grab a completely new block from the system pool. Relies on malloc()
@@ -553,7 +547,12 @@ static void *alloc_pool(struct pool_rec *p, size_t reqsz, int exact) {
char *new_first_avail;
if (reqsz == 0) {
- /* Don't try to allocate memory of zero length. */
+ /* Don't try to allocate memory of zero length.
+ *
+ * This should NOT happen normally; if it does, by returning NULL we
+ * almost guarantee a null pointer dereference.
+ */
+ errno = EINVAL;
return NULL;
}
diff --git a/src/support.c b/src/support.c
index 44e6ff9..2341dce 100644
--- a/src/support.c
+++ b/src/support.c
@@ -2,7 +2,7 @@
* ProFTPD - FTP server daemon
* Copyright (c) 1997, 1998 Public Flood Software
* Copyright (c) 1999, 2000 MacGyver aka Habeeb J. Dihu <macgyver at tos.net>
- * Copyright (c) 2001-2013 The ProFTPD Project team
+ * Copyright (c) 2001-2015 The ProFTPD Project team
*
* 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
@@ -26,8 +26,6 @@
/* Various basic support routines for ProFTPD, used by all modules
* and not specific to one or another.
- *
- * $Id: support.c,v 1.120 2013-08-07 16:35:27 castaglia Exp $
*/
#include "conf.h"
@@ -654,7 +652,7 @@ void pr_getopt_reset(void) {
defined(FREEBSD7) || defined(FREEBSD8) || defined(FREEBSD9) || \
defined(FREEBSD10) || \
defined(DARWIN7) || defined(DARWIN8) || defined(DARWIN9) || \
- defined(DARWIN10) || defined(DARWIN11)
+ defined(DARWIN10) || defined(DARWIN11) || defined(DARWIN12)
optreset = 1;
opterr = 1;
optind = 1;
diff --git a/tests/api/fsio.c b/tests/api/fsio.c
index 5efb21b..3b4b360 100644
--- a/tests/api/fsio.c
+++ b/tests/api/fsio.c
@@ -172,6 +172,22 @@ START_TEST (fs_dircat_test) {
fail_unless(res == 0, "Failed to concatenate two empty paths");
fail_unless(strcmp(buf, ok) == 0, "Expected concatenated dir '%s', got '%s'",
ok, buf);
+
+ a = "/foo";
+ b = "";
+ ok = "/foo/";
+ res = pr_fs_dircat(buf, sizeof(buf)-1, a, b);
+ fail_unless(res == 0, "Failed to concatenate two empty paths");
+ fail_unless(strcmp(buf, ok) == 0, "Expected concatenated dir '%s', got '%s'",
+ ok, buf);
+
+ a = "";
+ b = "/bar";
+ ok = "/bar/";
+ res = pr_fs_dircat(buf, sizeof(buf)-1, a, b);
+ fail_unless(res == 0, "Failed to concatenate two empty paths");
+ fail_unless(strcmp(buf, ok) == 0, "Expected concatenated dir '%s', got '%s'",
+ ok, buf);
}
END_TEST
diff --git a/tests/api/str.c b/tests/api/str.c
index fc9ecf0..a05de2c 100644
--- a/tests/api/str.c
+++ b/tests/api/str.c
@@ -230,10 +230,11 @@ START_TEST (sreplace_enospc_test) {
char *fmt = NULL, *res;
size_t bufsz = 8192;
- fmt = palloc(p, bufsz);
+ fmt = palloc(p, bufsz + 1);
memset(fmt, ' ', bufsz);
fmt[bufsz-2] = '%';
fmt[bufsz-1] = 'a';
+ fmt[bufsz] = '\0';
res = sreplace(p, fmt, "%a", "foo", NULL);
fail_unless(res == NULL, "Failed to reject too-long buffer");
diff --git a/utils/Makefile.in b/utils/Makefile.in
index 527277f..c3d705e 100644
--- a/utils/Makefile.in
+++ b/utils/Makefile.in
@@ -25,5 +25,5 @@ clean:
rm -f *.o
depend:
- makedepend $(CPPFLAGS) -Y *.c 2>/dev/null
- makedepend $(CPPFLAGS) -Y -fMakefile.in *.c 2>/dev/null
+ $(MAKEDEPEND) $(CPPFLAGS) *.c 2>/dev/null
+ $(MAKEDEPEND) $(CPPFLAGS) -fMakefile.in *.c 2>/dev/null
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-proftpd/proftpd-dfsg.git
More information about the Pkg-proftpd-maintainers
mailing list