diff --git a/CMakeLists.txt b/CMakeLists.txt index eebdc6bb..ba0cab25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -460,6 +460,7 @@ if(NOT MSVC) check_cxx_symbol_exists(mkdtemp stdlib.h HAVE_MKDTEMP) check_cxx_symbol_exists(accept4 sys/socket.h HAVE_ACCEPT4) check_cxx_symbol_exists(strnlen string.h HAVE_STRNLEN) + check_cxx_symbol_exists(strlcpy string.h ZMQ_HAVE_STRLCPY) else() set(HAVE_STRNLEN 1) endif() diff --git a/builds/cmake/platform.hpp.in b/builds/cmake/platform.hpp.in index 9f56575f..a95d9d94 100644 --- a/builds/cmake/platform.hpp.in +++ b/builds/cmake/platform.hpp.in @@ -51,6 +51,7 @@ #cmakedefine ZMQ_HAVE_PTHREAD_SET_AFFINITY #cmakedefine HAVE_ACCEPT4 #cmakedefine HAVE_STRNLEN +#cmakedefine ZMQ_HAVE_STRLCPY #cmakedefine ZMQ_HAVE_IPC diff --git a/configure.ac b/configure.ac index f6619cfe..43a74250 100644 --- a/configure.ac +++ b/configure.ac @@ -751,6 +751,20 @@ AC_COMPILE_IFELSE( AC_MSG_RESULT([no]) ]) +# string.h doesn't seem to be included by default in Fedora 30 +AC_MSG_CHECKING([whether strlcpy is available]) +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include ]], + [[char buf [100]; size_t bar = strlcpy (buf, "foo", 100); (void)bar; return 0;]]) + ],[ + AC_MSG_RESULT([yes]) + AC_DEFINE(ZMQ_HAVE_STRLCPY, [1], + [strlcpy is available]) + ],[ + AC_MSG_RESULT([no]) +]) + # pthread_setname is non-posix, and there are at least 4 different implementations AC_MSG_CHECKING([whether signature of pthread_setname_np() has 1 argument]) AC_COMPILE_IFELSE( diff --git a/src/ws_engine.cpp b/src/ws_engine.cpp index 8d12170a..32a67bac 100644 --- a/src/ws_engine.cpp +++ b/src/ws_engine.cpp @@ -52,6 +52,8 @@ along with this program. If not, see . #endif #endif +#include + #include "tcp.hpp" #include "ws_engine.hpp" #include "session_base.hpp" @@ -71,6 +73,23 @@ along with this program. If not, see . #ifdef ZMQ_HAVE_WINDOWS #define strcasecmp _stricmp +#else +#ifndef ZMQ_HAVE_STRLCPY +static size_t strlcpy (char *dest_, const char *src_, const size_t dest_size_) +{ + size_t remain = dest_size_; + for (; remain && *src_; --remain, ++src_, ++dest_) { + *dest_ = *src_; + } + return dest_size_ - remain; +} +#endif +template +static int strcpy_s (char (&dest_)[size], const char *const src_) +{ + const size_t res = strlcpy (dest_, src_, size); + return res >= size ? ERANGE : 0; +} #endif // OSX uses a different name for this socket option @@ -440,7 +459,7 @@ bool zmq::ws_engine_t::server_handshake () strcasecmp ("upgrade", _header_value) == 0; else if (strcasecmp ("Sec-WebSocket-Key", _header_name) == 0) - strcpy (_websocket_key, _header_value); + strcpy_s (_websocket_key, _header_value); else if (strcasecmp ("Sec-WebSocket-Protocol", _header_name) == 0) { // Currently only the ZWS2.0 is supported @@ -453,7 +472,7 @@ bool zmq::ws_engine_t::server_handshake () p++; if (select_protocol (p)) { - strcpy (_websocket_protocol, p); + strcpy_s (_websocket_protocol, p); break; } @@ -820,11 +839,11 @@ bool zmq::ws_engine_t::client_handshake () strcasecmp ("upgrade", _header_value) == 0; else if (strcasecmp ("Sec-WebSocket-Accept", _header_name) == 0) - strcpy (_websocket_accept, _header_value); + strcpy_s (_websocket_accept, _header_value); else if (strcasecmp ("Sec-WebSocket-Protocol", _header_name) == 0) { if (select_protocol (_header_value)) - strcpy (_websocket_protocol, _header_value); + strcpy_s (_websocket_protocol, _header_value); } _client_handshake_state = client_header_field_cr; } else if (_header_value_position + 1 > MAX_HEADER_VALUE_LENGTH)