static int telnet_waitsocket(ZBX_SOCKET socket_fd, int mode) { const char *__function_name = "telnet_waitsocket"; struct timeval tv; int rc; fd_set fd, *readfd = NULL, *writefd = NULL; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); tv.tv_sec = 0; tv.tv_usec = 100000; /* 1/10 sec */ FD_ZERO(&fd); FD_SET(socket_fd, &fd); if (WAIT_READ == mode) readfd = &fd; else writefd = &fd; rc = select((int)(socket_fd + 1), readfd, writefd, NULL, &tv); if (ZBX_PROTO_ERROR == rc) { zabbix_log(LOG_LEVEL_DEBUG, "%s() rc:%d errno:%d error:[%s]", __function_name, rc, zbx_socket_last_error(), strerror_from_system(zbx_socket_last_error())); } zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __function_name, rc); return rc; }
static ssize_t telnet_socket_write(ZBX_SOCKET socket_fd, const void *buf, size_t count) { const char *__function_name = "telnet_socket_write"; ssize_t rc; int error; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); while (ZBX_PROTO_ERROR == (rc = ZBX_TCP_WRITE(socket_fd, buf, count))) { error = zbx_socket_last_error(); /* zabbix_log() resets the error code */ zabbix_log(LOG_LEVEL_DEBUG, "%s() rc:%d errno:%d error:[%s]", __function_name, rc, error, strerror_from_system(error)); #ifdef _WINDOWS if (WSAEWOULDBLOCK == error) #else if (EAGAIN == error) #endif { telnet_waitsocket(socket_fd, WAIT_WRITE); continue; } break; } zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __function_name, rc); return rc; }
ZBX_THREAD_ENTRY(trapper_thread, args) { double sec = 0.0; zbx_socket_t s; process_type = ((zbx_thread_args_t *)args)->process_type; server_num = ((zbx_thread_args_t *)args)->server_num; process_num = ((zbx_thread_args_t *)args)->process_num; zabbix_log(LOG_LEVEL_INFORMATION, "%s #%d started [%s #%d]", get_program_type_string(program_type), server_num, get_process_type_string(process_type), process_num); memcpy(&s, (zbx_socket_t *)((zbx_thread_args_t *)args)->args, sizeof(zbx_socket_t)); #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL) zbx_tls_init_child(); find_psk_in_cache = DCget_psk_by_identity; #endif zbx_setproctitle("%s #%d [connecting to the database]", get_process_type_string(process_type), process_num); DBconnect(ZBX_DB_CONNECT_NORMAL); for (;;) { zbx_handle_log(); zbx_setproctitle("%s #%d [processed data in " ZBX_FS_DBL " sec, waiting for connection]", get_process_type_string(process_type), process_num, sec); update_selfmon_counter(ZBX_PROCESS_STATE_IDLE); /* Trapper has to accept all types of connections it can accept with the specified configuration. */ /* Only after receiving data it is known who has sent them and one can decide to accept or discard */ /* the data. */ if (SUCCEED == zbx_tcp_accept(&s, ZBX_TCP_SEC_TLS_CERT | ZBX_TCP_SEC_TLS_PSK | ZBX_TCP_SEC_UNENCRYPTED)) { zbx_timespec_t ts; /* get connection timestamp */ zbx_timespec(&ts); update_selfmon_counter(ZBX_PROCESS_STATE_BUSY); zbx_setproctitle("%s #%d [processing data]", get_process_type_string(process_type), process_num); sec = zbx_time(); process_trapper_child(&s, &ts); sec = zbx_time() - sec; zbx_tcp_unaccept(&s); } else if (EINTR != zbx_socket_last_error()) { zabbix_log(LOG_LEVEL_WARNING, "failed to accept an incoming connection: %s", zbx_socket_strerror()); } } }
static ssize_t telnet_socket_read(ZBX_SOCKET socket_fd, void *buf, size_t count) { const char *__function_name = "telnet_socket_read"; ssize_t rc; int error; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); while (ZBX_PROTO_ERROR == (rc = ZBX_TCP_READ(socket_fd, buf, count))) { error = zbx_socket_last_error(); /* zabbix_log() resets the error code */ zabbix_log(LOG_LEVEL_DEBUG, "%s() rc:%d errno:%d error:[%s]", __function_name, rc, error, strerror_from_system(error)); #ifdef _WINDOWS if (WSAEWOULDBLOCK == error) #else if (EAGAIN == error) #endif { /* wait and if there is still an error or no input available */ /* we assume the other side has nothing more to say */ if (1 > (rc = telnet_waitsocket(socket_fd, WAIT_READ))) goto ret; continue; } break; } /* when ZBX_TCP_READ returns 0, it means EOF - let's consider it a permanent error */ /* note that if telnet_waitsocket() is zero, it is not a permanent condition */ if (0 == rc) rc = ZBX_PROTO_ERROR; ret: zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __function_name, rc); return rc; }
ZBX_THREAD_ENTRY(listener_thread, args) { #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL) char *msg = NULL; #endif int ret; zbx_socket_t s; assert(args); assert(((zbx_thread_args_t *)args)->args); process_type = ((zbx_thread_args_t *)args)->process_type; server_num = ((zbx_thread_args_t *)args)->server_num; process_num = ((zbx_thread_args_t *)args)->process_num; zabbix_log(LOG_LEVEL_INFORMATION, "%s #%d started [%s #%d]", get_program_type_string(program_type), server_num, get_process_type_string(process_type), process_num); memcpy(&s, (zbx_socket_t *)((zbx_thread_args_t *)args)->args, sizeof(zbx_socket_t)); zbx_free(args); #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL) zbx_tls_init_child(); #endif while (ZBX_IS_RUNNING()) { zbx_setproctitle("listener #%d [waiting for connection]", process_num); ret = zbx_tcp_accept(&s, configured_tls_accept_modes); zbx_update_env(zbx_time()); if (SUCCEED == ret) { zbx_setproctitle("listener #%d [processing request]", process_num); if ('\0' != *CONFIG_HOSTS_ALLOWED && SUCCEED == (ret = zbx_tcp_check_allowed_peers(&s, CONFIG_HOSTS_ALLOWED))) { #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL) if (ZBX_TCP_SEC_TLS_CERT != s.connection_type || SUCCEED == (ret = zbx_check_server_issuer_subject(&s, &msg))) #endif { process_listener(&s); } } zbx_tcp_unaccept(&s); } if (SUCCEED == ret || EINTR == zbx_socket_last_error()) continue; #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL) if (NULL != msg) { zabbix_log(LOG_LEVEL_WARNING, "failed to accept an incoming connection: %s", msg); zbx_free(msg); } else #endif { zabbix_log(LOG_LEVEL_WARNING, "failed to accept an incoming connection: %s", zbx_socket_strerror()); } if (ZBX_IS_RUNNING()) zbx_sleep(1); } #ifdef _WINDOWS ZBX_DO_EXIT(); zbx_thread_exit(EXIT_SUCCESS); #endif }
int telnet_execute(ZBX_SOCKET socket_fd, const char *command, AGENT_RESULT *result, const char *encoding) { const char *__function_name = "telnet_execute"; char buf[MAX_BUFFER_LEN]; size_t sz, offset; int rc, ret = FAIL; char *command_lf = NULL, *command_crlf = NULL; size_t i, offset_lf, offset_crlf; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); /* `command' with multiple lines may contain CR+LF from the browser; */ /* it should be converted to plain LF to remove echo later on properly */ offset_lf = strlen(command); command_lf = zbx_malloc(command_lf, offset_lf + 1); zbx_strlcpy(command_lf, command, offset_lf + 1); convert_telnet_to_unix_eol(command_lf, &offset_lf); /* telnet protocol requires that end-of-line is transferred as CR+LF */ command_crlf = zbx_malloc(command_crlf, offset_lf * 2 + 1); convert_unix_to_telnet_eol(command_lf, offset_lf, command_crlf, &offset_crlf); telnet_socket_write(socket_fd, command_crlf, offset_crlf); telnet_socket_write(socket_fd, "\r\n", 2); sz = sizeof(buf); offset = 0; while (ZBX_PROTO_ERROR != (rc = telnet_read(socket_fd, buf, &sz, &offset))) { if (prompt_char == telnet_lastchar(buf, offset)) break; } convert_telnet_to_unix_eol(buf, &offset); zabbix_log(LOG_LEVEL_DEBUG, "%s() command output:'%.*s'", __function_name, (int)offset, buf); if (ZBX_PROTO_ERROR == rc) { SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot find prompt after command execution: %s", strerror_from_system(zbx_socket_last_error()))); goto fail; } telnet_rm_echo(buf, &offset, command_lf, offset_lf); /* multi-line commands may have returned additional prompts; */ /* this is not a perfect solution, because in case of multiple */ /* multi-line shell statements these prompts might appear in */ /* the middle of the output, but we still try to be helpful by */ /* removing additional prompts at least from the beginning */ for (i = 0; i < offset_lf; i++) { if ('\n' == command_lf[i]) { if (SUCCEED != telnet_rm_echo(buf, &offset, "$ ", 2) && SUCCEED != telnet_rm_echo(buf, &offset, "# ", 2) && SUCCEED != telnet_rm_echo(buf, &offset, "> ", 2) && SUCCEED != telnet_rm_echo(buf, &offset, "% ", 2)) { break; } } } telnet_rm_echo(buf, &offset, "\n", 1); telnet_rm_prompt(buf, &offset); zabbix_log(LOG_LEVEL_DEBUG, "%s() stripped command output:'%.*s'", __function_name, (int)offset, buf); if (MAX_BUFFER_LEN == offset) offset--; buf[offset] = '\0'; SET_STR_RESULT(result, convert_to_utf8(buf, offset, encoding)); ret = SUCCEED; fail: zbx_free(command_lf); zbx_free(command_crlf); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret)); return ret; }