diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 578d567..6b13f74 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,9 @@ on: - master - develop pull_request: + branches: + - master + - develop jobs: Build: diff --git a/.gitignore b/.gitignore index 01f9cb9..8745738 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -build/ -.vscode/ \ No newline at end of file +/build/ +/.vscode/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 17e0766..434b1ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) project(libtelnet VERSION 0.30.0 LANGUAGES C @@ -6,6 +6,11 @@ project(libtelnet set(PROJECT_DESCRIPTION "TELNET protocol handling library") set(PROJECT_HOMEPAGE_URL https://github.com/seanmiddleditch/libtelne) +# Enable CMAKE Policy +if(${CMAKE_VERSION} VERSION_LESS 3.10) + cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) +endif() + if (MSVC) add_definitions(-D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS) if (LIBTELNET_STRICT) @@ -27,6 +32,13 @@ target_include_directories(libtelnet ${CMAKE_CURRENT_SOURCE_DIR} ) +find_package(ZLIB) +if(${ZLIB_FOUND}) + target_compile_definitions(libtelnet PUBLIC HAVE_ZLIB) + target_include_directories(libtelnet PRIVATE ${ZLIB_INCLUDE_DIRS}) + target_link_libraries(libtelnet PRIVATE ${ZLIB_LIBRARIES}) +endif() + add_subdirectory(util) add_subdirectory(doc) add_subdirectory(test) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 2147c1a..5e1231a 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,8 +1,8 @@ find_package(Doxygen) -add_subdirectory(man) - if (DOXYGEN_FOUND) + add_subdirectory(man) + configure_file(Doxyfile.in Doxyfile) add_custom_target(doc_doxygen ALL COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT} diff --git a/libtelnet.c b/libtelnet.c index 71dc5f3..3d09e53 100644 --- a/libtelnet.c +++ b/libtelnet.c @@ -407,7 +407,6 @@ static void _negotiate(telnet_t *telnet, unsigned char telopt) { break; case Q_WANTNO_OP: _set_rfc1143(telnet, telopt, Q_US(q), Q_YES); - NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt); _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0, "DONT answered by WILL"); break; @@ -437,7 +436,8 @@ static void _negotiate(telnet_t *telnet, unsigned char telopt) { break; case Q_WANTNO_OP: _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES); - NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt); + _send_negotiate(telnet, TELNET_DO, telopt); + NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt); break; case Q_WANTYES: case Q_WANTYES_OP: @@ -465,7 +465,6 @@ static void _negotiate(telnet_t *telnet, unsigned char telopt) { break; case Q_WANTNO_OP: _set_rfc1143(telnet, telopt, Q_YES, Q_HIM(q)); - NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt); _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0, "WONT answered by DO"); break; @@ -491,12 +490,12 @@ static void _negotiate(telnet_t *telnet, unsigned char telopt) { break; case Q_WANTNO: _set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q)); - NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt); + NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt); break; case Q_WANTNO_OP: _set_rfc1143(telnet, telopt, Q_WANTYES, Q_HIM(q)); _send_negotiate(telnet, TELNET_WILL, telopt); - NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt); + NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt); break; case Q_WANTYES: case Q_WANTYES_OP: @@ -553,7 +552,7 @@ static int _environ_telnet(telnet_t *telnet, unsigned char type, ev.type = TELNET_EV_ENVIRON; telnet->eh(telnet, &ev, telnet->ud); - return 1; + return 0; } /* very second byte must be VAR or USERVAR, if present */ @@ -657,7 +656,7 @@ static int _environ_telnet(telnet_t *telnet, unsigned char type, /* clean up */ free(values); - return 1; + return 0; } /* process an MSSP subnegotiation buffer */ @@ -849,17 +848,14 @@ static int _subnegotiate(telnet_t *telnet) { * start handling the compressed stream if it's not already. */ case TELNET_TELOPT_COMPRESS2: - if (telnet->sb_telopt == TELNET_TELOPT_COMPRESS2) { - if (_init_zlib(telnet, 0, 1) != TELNET_EOK) - return 0; + if (_init_zlib(telnet, 0, 1) != TELNET_EOK) + return 0; - /* notify app that compression was enabled */ - ev.type = TELNET_EV_COMPRESS; - ev.compress.state = 1; - telnet->eh(telnet, &ev, telnet->ud); - return 1; - } - return 0; + /* notify app that compression was enabled */ + ev.type = TELNET_EV_COMPRESS; + ev.compress.state = 1; + telnet->eh(telnet, &ev, telnet->ud); + return 1; #endif /* defined(HAVE_ZLIB) */ /* specially handled subnegotiation telopt types */ @@ -1613,6 +1609,9 @@ void telnet_ttype_send(telnet_t *telnet) { void telnet_ttype_is(telnet_t *telnet, const char* ttype) { static const unsigned char IS[] = { TELNET_IAC, TELNET_SB, TELNET_TELOPT_TTYPE, TELNET_TTYPE_IS }; + if (!ttype) { + ttype = "NVT"; + } _sendu(telnet, IS, sizeof(IS)); _send(telnet, ttype, strlen(ttype)); telnet_finish_sb(telnet); diff --git a/util/telnet-chatd.c b/util/telnet-chatd.c index 96800fa..12cf44a 100644 --- a/util/telnet-chatd.c +++ b/util/telnet-chatd.c @@ -167,6 +167,7 @@ static void _online(const char *line, size_t overflow, void *ud) { _message(user->name, "** HAS QUIT **"); free(user->name); user->name = 0; + telnet_free(user->telnet); return; } @@ -177,7 +178,7 @@ static void _online(const char *line, size_t overflow, void *ud) { static void _input(struct user_t *user, const char *buffer, size_t size) { unsigned int i; - for (i = 0; i != size; ++i) + for (i = 0; user->sock != -1 && i != size; ++i) linebuffer_push(user->linebuf, sizeof(user->linebuf), &user->linepos, (char)buffer[i], _online, user); } @@ -307,7 +308,7 @@ int main(int argc, char **argv) { } /* new connection */ - if (pfd[MAX_USERS].revents & POLLIN) { + if (pfd[MAX_USERS].revents & (POLLIN | POLLERR | POLLHUP)) { /* acept the sock */ addrlen = sizeof(addr); if ((client_sock = accept(listen_sock, (struct sockaddr *)&addr, @@ -345,20 +346,19 @@ int main(int argc, char **argv) { if (users[i].sock == -1) continue; - if (pfd[i].revents & POLLIN) { + if (pfd[i].revents & (POLLIN | POLLERR | POLLHUP)) { if ((rs = recv(users[i].sock, buffer, sizeof(buffer), 0)) > 0) { telnet_recv(users[i].telnet, buffer, rs); } else if (rs == 0) { printf("Connection closed.\n"); close(users[i].sock); + users[i].sock = -1; if (users[i].name != 0) { _message(users[i].name, "** HAS DISCONNECTED **"); free(users[i].name); users[i].name = 0; } telnet_free(users[i].telnet); - users[i].sock = -1; - break; } else if (errno != EINTR) { fprintf(stderr, "recv(client) failed: %s\n", strerror(errno)); diff --git a/util/telnet-client.c b/util/telnet-client.c index aff4558..5c0a7f8 100644 --- a/util/telnet-client.c +++ b/util/telnet-client.c @@ -225,7 +225,7 @@ int main(int argc, char **argv) { /* loop while both connections are open */ while (poll(pfd, 2, -1) != -1) { /* read from stdin */ - if (pfd[0].revents & POLLIN) { + if (pfd[0].revents & (POLLIN | POLLERR | POLLHUP)) { if ((rs = read(STDIN_FILENO, buffer, sizeof(buffer))) > 0) { _input(buffer, rs); } else if (rs == 0) { @@ -238,7 +238,7 @@ int main(int argc, char **argv) { } /* read from client */ - if (pfd[1].revents & POLLIN) { + if (pfd[1].revents & (POLLIN | POLLERR | POLLHUP)) { if ((rs = recv(sock, buffer, sizeof(buffer), 0)) > 0) { telnet_recv(telnet, buffer, rs); } else if (rs == 0) { diff --git a/util/telnet-proxy.c b/util/telnet-proxy.c index 32d393d..16d8a33 100644 --- a/util/telnet-proxy.c +++ b/util/telnet-proxy.c @@ -464,7 +464,7 @@ int main(int argc, char **argv) { /* loop while both connections are open */ while (poll(pfd, 2, -1) != -1) { /* read from server */ - if (pfd[0].revents & POLLIN) { + if (pfd[0].revents & (POLLIN | POLLERR | POLLHUP)) { if ((rs = recv(server.sock, buffer, sizeof(buffer), 0)) > 0) { telnet_recv(server.telnet, buffer, rs); } else if (rs == 0) { @@ -480,7 +480,7 @@ int main(int argc, char **argv) { } /* read from client */ - if (pfd[1].revents & POLLIN) { + if (pfd[1].revents & (POLLIN | POLLERR | POLLHUP)) { if ((rs = recv(client.sock, buffer, sizeof(buffer), 0)) > 0) { telnet_recv(client.telnet, buffer, rs); } else if (rs == 0) {