/****************************************************************************** * Copyright (c) 2000-2019 Ericsson Telecom AB * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * Contributors: * Tibor Csondes - initial implementation and initial documentation * Akos Cserveni * Elemer Lelik * Gabor Szalai * Gabor Tatarka * Gergely Futo * Istvan Sandor * Peter Dimitrov * Peter Kremer * Tibor Bende * Zoltan Medve ******************************************************************************/ // // File: TELNETasp_PT.cc // Description: TELNET testport source file // Rev: R9A // Prodnr: CNL 113 320 // #include "TELNETasp_PT.hh" #define TELCMDS 1 #define TELOPTS 1 #include #include #include #include #if ( defined TTCN3_VERSION_MONOTONE ) && ! ( TTCN3_VERSION_MONOTONE <= 1100099) #include "pattern.hh" char* TTCN_pattern_to_regexp_telnet(const char* patt){ return TTCN_pattern_to_regexp(patt); } #else #ifndef TTCN_pattern_to_regexp extern char* TTCN_pattern_to_regexp(const char*,int); char* TTCN_pattern_to_regexp_telnet(const char* patt){ return TTCN_pattern_to_regexp(patt,1); } #endif #endif namespace TELNETasp__PortType { TELNETasp__PT::TELNETasp__PT(const char *par_port_name) : TELNETasp__PT_BASE(par_port_name), window_size(par_port_name) { dont_close_fd=-1; ctrl_hostname = NULL; ctrl_portnum = 0; ctrl_username = NULL; ctrl_password = NULL; ctrl_domain = NULL; ctrl_readmode = READMODE_BUFFERED; ctrl_login_skipped = false; ctrl_detect_server_disconnected = false; ctrl_detect_connection_establishment_result = false; ctrl_client_cleanup_linefeed = true; ctrl_terminal_type = NULL; ctrl_echo = false; ctrl_CRLF = false; echobuf = ""; config_finished = false; asp_params = NULL; map_poll_timeout=10000; // 10 sec = 10000 millisec ctrl_username_client = NULL; ctrl_password_client = NULL; ctrl_server_prompt = NULL; server_mode_def = false; ctrl_server_attach_prompt = true; ctrl_detect_client_disconnected = false; ctrl_server_failsafe_sending = false; port_mapped = false; fd_server = -1; isClientLoggedIn = false; isRawRegexpPrompt = false; pass_prompt_send = false; emptyEcho = false; suppressed = false; login_incorrect = false; ctrl_password_prompt = NULL; ctrl_loginname_prompt = NULL; debugAllowed = false; } TELNETasp__PT::~TELNETasp__PT() { reset_configuration(); } void TELNETasp__PT::set_parameter(const char *parameter_name, const char *parameter_value) { if (config_finished) { reset_configuration(); config_finished = false; } if(strcmp( "MAP_RECV_TIMEOUT", parameter_name) == 0) { map_poll_timeout = atoi ( parameter_value ); log_debug( "%s: Reading testport parameter: MAP_RECV_TIMEOUT = %d", port_name, map_poll_timeout ); } else if(strcmp( "CTRL_HOSTNAME", parameter_name) == 0) InitStrPar(ctrl_hostname, parameter_name, parameter_value); else if(strcmp( "CTRL_PORTNUM", parameter_name) == 0) { ctrl_portnum = atoi ( parameter_value ); log_debug( "%s: Reading testport parameter: CTRL_PORTNUM = %d", port_name, ctrl_portnum ); } else if(strcmp("CTRL_USERNAME", parameter_name) == 0) InitStrPar(ctrl_username, parameter_name, parameter_value); else if(strcmp("CTRL_PASSWORD", parameter_name) == 0) { //InitStrPar(ctrl_password, parameter_name, parameter_value); InitStrPar(ctrl_password, NULL, parameter_value); log_debug( "%s: Reading testport parameter: CTRL_PASSWORD", port_name); } else if(strcmp("CTRL_DOMAIN", parameter_name) == 0) InitStrPar(ctrl_domain, parameter_name, parameter_value); else if(strcmp("CTRL_READMODE", parameter_name) == 0) { log_debug( "%s: Reading testport parameter: %s = %s", port_name, parameter_name, parameter_value ); if(strcmp(parameter_value, "buffered") == 0) ctrl_readmode = READMODE_BUFFERED; else if(strcmp(parameter_value, "unbuffered") == 0) ctrl_readmode = READMODE_UNBUFFERED; else TTCN_error("Invalid value for: CTRL_READMODE"); } else if(strncmp("PROMPT", parameter_name, 6) == 0) { if(strlen(parameter_name) < 7) TTCN_error("%s: PROMPT " "parameters should be given as PROMPT := " "\"value\".", port_name); errno = 0; size_t prompt_id = atoi(parameter_name + 6); if(errno) TTCN_error("%s: error converting string \"%s\" in parameter " "name \"%s\" to number.", port_name, parameter_name + 6, parameter_name); if(strlen(parameter_value)!=0) { log_debug( "%s: Reading testport parameter: " "%s = %s", port_name, parameter_name, parameter_value ); prompt_list.set_prompt(prompt_id, parameter_value, false); } else TTCN_error("PROMPT parameter must contain at least one character"); } else if(strncmp("REGEX_PROMPT", parameter_name, 12) == 0) { if(strlen(parameter_name) < 13) TTCN_error("%s: REGEX_PROMPT " "parameters should be given as REGEX_PROMPT := " "\"value\".", port_name); errno = 0; size_t prompt_id = atoi(parameter_name + 12); if(errno) TTCN_error("%s: error converting string \"%s\" in parameter " "name \"%s\" to number.", port_name, parameter_name + 12, parameter_name); if(strlen(parameter_value)!=0) { log_debug( "%s: Reading testport parameter: " "%s = %s", port_name, parameter_name, parameter_value ); prompt_list.set_prompt(prompt_id, parameter_value, true); } else TTCN_error("REGEX_PROMPT parameter must contain at least one character"); } else if(strncmp("RAW_REGEX_PROMPT", parameter_name, 16) == 0) { if(strlen(parameter_name) < 16) TTCN_error("%s: REGEX_PROMPT " "parameters should be given as RAW_REGEX_PROMPT := " "\"value\".", port_name); errno = 0; size_t prompt_id = atoi(parameter_name + 16); if(errno) TTCN_error("%s: error converting string \"%s\" in parameter " "name \"%s\" to number.", port_name, parameter_name + 12, parameter_name); if(strlen(parameter_value)!=0) { log_debug( "%s: Reading testport parameter: " "%s = %s", port_name, parameter_name, parameter_value ); prompt_list.set_prompt(prompt_id, parameter_value, true,true); } else TTCN_error("REGEX_PROMPT parameter must contain at least one character"); } else if(strcmp("API_REGEXP_PROMPT_MODE", parameter_name) == 0) { log_debug( "%s: Reading testport parameter: %s = %s", port_name, parameter_name, parameter_value ); if(strcasecmp(parameter_value, "raw") == 0) isRawRegexpPrompt = true; else if(strcasecmp(parameter_value, "normal") == 0) isRawRegexpPrompt = false; else TTCN_error( "Invalid value for: API_REGEXP_PROMPT_MODE" ); } else if(strcmp("CTRL_LOGIN_SKIPPED", parameter_name) == 0) { log_debug( "%s: Reading testport parameter: %s = %s", port_name, parameter_name, parameter_value ); if(strcasecmp(parameter_value, "yes") == 0) ctrl_login_skipped = true; else if(strcasecmp(parameter_value, "no") == 0) ctrl_login_skipped = false; else TTCN_error( "Invalid value for: CTRL_LOGIN_SKIPPED" ); } else if(strcmp("CTRL_DETECT_SERVER_DISCONNECTED", parameter_name) == 0) { log_debug( "%s: Reading testport parameter: %s = %s", port_name, parameter_name, parameter_value ); if(strcasecmp(parameter_value, "yes") == 0) ctrl_detect_server_disconnected = true; else if(strcasecmp(parameter_value, "no") == 0) ctrl_detect_server_disconnected = false; else TTCN_error("Invalid value for: CTRL_DETECT_SERVER_DISCONNECTED"); } else if(strcmp("CTRL_DETECT_CONNECTION_ESTABLISHMENT_RESULT", parameter_name) == 0) { log_debug( "%s: Reading testport parameter: %s = %s", port_name, parameter_name, parameter_value ); if(strcasecmp(parameter_value, "yes") == 0) ctrl_detect_connection_establishment_result = true; else if(strcasecmp(parameter_value, "no") == 0) ctrl_detect_connection_establishment_result = false; else TTCN_error("Invalid value for: CTRL_DETECT_CONNECTION_ESTABLISHMENT_RESULT"); } else if(strcmp("CTRL_TERMINAL_TYPE", parameter_name) == 0) InitStrPar( ctrl_terminal_type, parameter_name, parameter_value ); else if(strcmp("CTRL_ECHO", parameter_name) == 0) { log_debug( "%s: Reading testport parameter: %s = %s", port_name, parameter_name, parameter_value ); if(strcasecmp(parameter_value, "yes") == 0) ctrl_echo = true; else if(strcasecmp(parameter_value, "no") == 0) ctrl_echo = false; else TTCN_error( "Invalid value for: CTRL_ECHO" ); } else if(strcmp("CTRL_CRLF", parameter_name) == 0) { log_debug( "%s: Reading testport parameter: %s = %s", port_name, parameter_name, parameter_value ); if(strcasecmp(parameter_value, "yes") == 0) ctrl_CRLF = true; else if(strcasecmp(parameter_value, "no") == 0) ctrl_CRLF = false; else TTCN_error( "Invalid value for: CTRL_CRLF" ); } else if(strcmp("CTRL_WINDOW_WIDTH", parameter_name) == 0) { window_size.set_width(atoi(parameter_value)); log_debug( "%s: Reading testport parameter: CTRL_WINDOW_WIDTH = %d", port_name, window_size.get_width() ); } else if(strcmp("CTRL_WINDOW_HEIGHT", parameter_name) == 0) { window_size.set_height(atoi(parameter_value)); log_debug( "%s: Reading testport parameter: CTRL_WINDOW_HEIGHT = %d", port_name, window_size.get_height() ); } else if (strcmp("CTRL_USERNAME_CLIENT", parameter_name) == 0) InitStrPar(ctrl_username_client, parameter_name, parameter_value); else if (strcmp("CTRL_PASSWORD_CLIENT", parameter_name) == 0) InitStrPar(ctrl_password_client, parameter_name, parameter_value); else if ( strcmp(parameter_name, "CTRL_MODE") == 0){ log_debug("%s: Reading testport parameter: %s = %s", port_name, parameter_name, parameter_value ); server_mode_def = true; if (strcmp(parameter_value, "server") == 0) server_mode = true; else if (strcmp(parameter_value, "client") == 0) server_mode = false; else TTCN_error("Invalid value for: CTRL_MODE"); } else if (strcmp(parameter_name, "CTRL_SERVER_PROMPT") == 0) InitStrPar(ctrl_server_prompt, parameter_name, parameter_value); else if (strcmp(parameter_name, "CTRL_PASSWORD_PROMPT") == 0) InitStrPar(ctrl_password_prompt, parameter_name, parameter_value); else if (strcmp(parameter_name, "CTRL_LOGINNAME_PROMPT") == 0) InitStrPar(ctrl_loginname_prompt, parameter_name, parameter_value); else if (strcmp(parameter_name, "CTRL_CLIENT_CLEANUP_LINEFEED") == 0){ log_debug( "%s: Reading testport parameter: %s = %s", port_name, parameter_name, parameter_value ); if(strcasecmp(parameter_value, "yes") == 0) ctrl_client_cleanup_linefeed = true; else if(strcasecmp(parameter_value, "no") == 0) ctrl_client_cleanup_linefeed = false; else TTCN_error( "Invalid value for: CTRL_CLIENT_CLEANUP_LINEFEED" ); } else if(strcmp(parameter_name, "CTRL_SERVER_ATTACH_PROMPT") == 0){ log_debug( "%s: Reading testport parameter: %s = %s", port_name, parameter_name, parameter_value ); if(strcasecmp(parameter_value, "yes") == 0) ctrl_server_attach_prompt = true; else if(strcasecmp(parameter_value, "no") == 0) ctrl_server_attach_prompt = false; else TTCN_error( "Invalid value for: CTRL_SERVER_ATTACH_PROMPT" ); } else if(strcmp(parameter_name, "CTRL_DETECT_CLIENT_DISCONNECTED") == 0){ log_debug( "%s: Reading testport parameter: %s = %s", port_name, parameter_name, parameter_value ); if(strcasecmp(parameter_value, "yes") == 0) ctrl_detect_client_disconnected = true; else if(strcasecmp(parameter_value, "no") == 0) ctrl_detect_client_disconnected = false; else TTCN_error( "Invalid value for: CTRL_DETECT_CLIENT_DISCONNECTED" ); } else if(strcmp(parameter_name, "CTRL_SERVER_FAILSAFE_SENDING") == 0){ log_debug( "%s: Reading testport parameter: %s = %s", port_name, parameter_name, parameter_value ); if(strcasecmp(parameter_value, "yes") == 0) ctrl_server_failsafe_sending = true; else if(strcasecmp(parameter_value, "no") == 0) ctrl_server_failsafe_sending = false; else TTCN_error( "Invalid value for: CTRL_SERVER_FAILSAFE_SENDING" ); } else if (!strcmp(parameter_name, "DEBUG")) { log_debug( "%s: Reading testport parameter: %s = %s", port_name, parameter_name, parameter_value ); if(strcasecmp(parameter_value, "yes") == 0) { debugAllowed = true; window_size.set_debug(true); prompt_list.set_debug(true); } else if(strcasecmp(parameter_value, "no") == 0) { debugAllowed = false; window_size.set_debug(false); prompt_list.set_debug(false); } else TTCN_error( "Invalid value for: DEBUG" ); } else if (strcmp(parameter_name, "empty_echo") == 0 ) { log_debug("%s: Reading testport parameter: %s = %s", port_name, parameter_name, parameter_value); if (strcmp(parameter_value, "yes") == 0) { emptyEcho = true; } else { log_debug("%s wasn't yes -> empty echo disabled.", parameter_value); } } else TTCN_warning("%s: unknown parameter: %s", port_name, parameter_name); } /*void TELNETasp__PT::Event_Handler(const fd_set *read_fds, const fd_set *write_fds, const fd_set *error_fds, double time_since_last_call) */ void TELNETasp__PT::Handle_Fd_Event_Readable(int fd) { log_debug("Handle_Fd_Event_Readable(int fd=%d)",fd); if (server_mode){ if( fd==fd_server){ //incoming connection arrived char addr[INET_ADDRSTRLEN]; struct sockaddr_in client; #if defined SOLARIS8 || LINUX || FREEBSD socklen_t #else /* SOLARIS or WIN32 */ int #endif addr_len = sizeof(client); if ( (nvtsock = accept(fd_server, (struct sockaddr*)&client, &addr_len)) < 0 ) TTCN_error("Error accepting connection"); inet_ntop(AF_INET, &(client.sin_addr), addr, sizeof(addr)); log_debug("Accepting connection from: %s on socket %d", addr , nvtsock); Handler_Remove_Fd_Read(fd_server); Handler_Add_Fd_Read(nvtsock); // FD_CLR(fd_server, &readfds); // FD_SET(nvtsock, &readfds); // Install_Handler(&readfds, NULL, NULL, 0.0); if (ctrl_login_skipped){ if(ctrl_server_attach_prompt){ if ( ::send(nvtsock, "\r\n", 2 , 0) < 0){ if(ctrl_server_failsafe_sending){ TTCN_warning("TCP send failed"); goto conn_setup_failed; } else{ TTCN_error("TCP send failed"); } } if ( ::send(nvtsock, ctrl_server_prompt, strlen(ctrl_server_prompt), 0) < 0){ if(ctrl_server_failsafe_sending){ TTCN_warning("TCP send failed"); goto conn_setup_failed; } else{ TTCN_error("TCP send failed"); } } } incoming_message(INTEGER(1)); isClientLoggedIn = true; if (fcntl(nvtsock, F_SETFL, O_NONBLOCK) == -1) { TTCN_error("fcntl(nvtsock, F_SETFL, O_NONBLOCK) failed: %d,%s",errno, strerror(errno)); } return; } //starting login procedure if ( ::send(nvtsock,"\r\n", 2,0 ) < 0){ if(ctrl_server_failsafe_sending){ TTCN_warning("TCP send failed"); goto conn_setup_failed; } else{ TTCN_error("TCP send failed"); } } if ( ::send(nvtsock,ctrl_loginname_prompt, strlen(ctrl_loginname_prompt),0 ) < 0){ if(ctrl_server_failsafe_sending){ TTCN_warning("TCP send failed"); goto conn_setup_failed; } else{ TTCN_error("TCP send failed"); } } return; conn_setup_failed: // Something went wrong during the connection set up // go back listening and close the socket close_connection(nvtsock); Handler_Add_Fd_Read(fd_server); return; } else if (fd==nvtsock){ recv_msg_from_client(nvtsock); } else {TTCN_error("Invalid file descriptor to read %d",fd);} } else { int res=RecvClrMsg(); // workaround for a strange issue if(res == -2){ return; // ignore OOB data } if (res < 0) { if(ctrl_detect_server_disconnected) return; else TTCN_error ("*** Socket error or the server closed the connection " "(in Event_Handler)."); } while(true) { size_t echo_pos; if(ctrl_echo==false && buf_strcmp((const char*)echobuf, ttcn_buf.get_data(), ttcn_buf.get_len(), echo_pos) && echo_pos == 0) { /*log_buffer("Before echo proc.:", ttcn_buf.get_data(), ttcn_buf.get_len());*/ ttcn_buf.set_pos(strlen((const char*)echobuf)); ttcn_buf.cut(); echobuf = ""; suppressed = true; /*log_buffer("After echo proc.:", ttcn_buf.get_data(), ttcn_buf.get_len());*/ if(!ttcn_buf.get_len()) return; } const unsigned char * bufptr = ttcn_buf.get_data(); int prompt_len; bool nl_found = false, prompt_found = false; size_t prompt_start_pos_prompt, prompt_start_pos_nl; if (ctrl_readmode == READMODE_UNBUFFERED) { nl_found = buf_strcmp("\n", bufptr, ttcn_buf.get_len(), prompt_start_pos_nl); if ((prompt_len = isPrompt(prompt_start_pos_prompt))>=0) prompt_found = true; /*If there is neither new line nor prompt in the buffer then simply return and wait for more data*/ if(!nl_found && !prompt_found) return; else if((nl_found && !prompt_found) || (nl_found && prompt_found && prompt_start_pos_nl < prompt_start_pos_prompt)) { if(prompt_start_pos_nl){ suppressed = false; incoming_message(CHARSTRING(prompt_start_pos_nl, (const char*)bufptr)); } ttcn_buf.set_pos(prompt_start_pos_nl+1); ttcn_buf.cut(); } else { //First send the data previous to the prompt ... if(prompt_start_pos_prompt) { suppressed = false; incoming_message(CHARSTRING(prompt_start_pos_prompt, (const char*)bufptr)); ttcn_buf.set_pos(prompt_start_pos_prompt); ttcn_buf.cut(); } //... and then send the prompt itself bufptr = ttcn_buf.get_data(); suppressed = false; incoming_message(CHARSTRING(prompt_len, (const char*)bufptr)); ttcn_buf.set_pos(prompt_len); ttcn_buf.cut(); } nl_found = false; prompt_found = false; if(!ttcn_buf.get_len()) return; } else { // READMODE_BUFFERED /* only send if the last line is prompt */ if ((prompt_len = isPrompt(prompt_start_pos_prompt))>=0) { // promptlen==0 is not checked here since it must contain // at least 1 character, that is checked in set_parameter() //First send the data previous to the prompt ... log_debug("Prompt start pos: %d", prompt_start_pos_prompt); if(prompt_start_pos_prompt) { int msg_end_pos = prompt_start_pos_prompt; if(ctrl_client_cleanup_linefeed){ while(msg_end_pos>0) { if(bufptr[msg_end_pos-1]!='\n') break; else msg_end_pos--; } } if(msg_end_pos){ suppressed = false; incoming_message(CHARSTRING(msg_end_pos, (const char*)bufptr)); } ttcn_buf.set_pos(prompt_start_pos_prompt); ttcn_buf.cut(); } if (emptyEcho && suppressed){ suppressed = false; incoming_message(""); } //... and then send the prompt itself bufptr = ttcn_buf.get_data(); suppressed = false; incoming_message(CHARSTRING(prompt_len, (const char*)bufptr)); ttcn_buf.set_pos(prompt_len); ttcn_buf.cut(); if(!ttcn_buf.get_len()) return; } return; } } // while } // server-mode else (client mode) } // TELNETasp__PT::Handle_Fd_Event_Readable void TELNETasp__PT::user_map(const char *system_port) { set_asp_params(); config_finished = true; suppressed = false; if (!server_mode_def){ TTCN_warning("Mode is not defined. Test Port will operate in client mode operation."); server_mode = false; } if((!server_mode) && (ctrl_portnum == 0)) // The portnum can be zero in server mode. The actual listen port is printed out in WARNING TTCN_error("Missing mandatory parameter: CTRL_PORTNUM"); struct sockaddr_in address; int enabled = 1; if (server_mode){ nvtsock=-1; if (port_mapped){ TTCN_warning("%s: user_map() was called to a mapped port", port_name); return; } if(ctrl_server_prompt == NULL) TTCN_error("Missing mandatory parameter: CTRL_SERVER_PROMPT"); if (ctrl_username_client == NULL && !ctrl_login_skipped) TTCN_error("Missing mandatory parameter: CTRL_USERNAME_CLIENT"); if (ctrl_password_client == NULL && !ctrl_login_skipped) TTCN_error("Missing mandatory parameter: CTRL_PASSWORD_CLIENT"); if (ctrl_loginname_prompt == NULL){ if ((ctrl_loginname_prompt = (char*)malloc(8*sizeof(char))) == NULL ) TTCN_error("Not enough memory"); strcpy(ctrl_loginname_prompt, "login: "); } if (ctrl_password_prompt == NULL){ if ((ctrl_password_prompt = (char*)malloc(11*sizeof(char))) == NULL ) TTCN_error("Not enough memory"); strcpy(ctrl_password_prompt, "password: "); } if ((fd_server = socket(AF_INET, SOCK_STREAM, 0)) < 0) TTCN_error("Socket creation failed"); log_debug( "%s: Server socket created: %d", port_name, fd_server); if ( setsockopt(fd_server, SOL_SOCKET, SO_REUSEADDR, &enabled, sizeof(int)) < 0) TTCN_error("setsockopt(SO_REUSEADDR) failed"); address.sin_family = AF_INET; address.sin_port = htons(ctrl_portnum); address.sin_addr.s_addr = htons(INADDR_ANY); memset(&(address.sin_zero), '\0', 8); if ( bind(fd_server, (struct sockaddr*)&address, sizeof(address)) < 0 ) TTCN_error("%s: Error bindig socket to port %d. Reason: %d %s",port_name ,ctrl_portnum,errno,strerror(errno)); if (listen(fd_server,1) < 0 ) TTCN_error("%s: Error listening on port %d",port_name ,ctrl_portnum); if(ctrl_portnum==0){ // ephemeral port, get the used one struct sockaddr_in sin; socklen_t len = sizeof(sin); if (getsockname(fd_server, (struct sockaddr *)&sin, &len) == -1){ TTCN_warning("%s : Can not get the listen port number errno:%d %s",port_name,errno,strerror(errno)); } else { ctrl_portnum=ntohs(sin.sin_port); TTCN_warning("%s : The TELNET listen port: %d",port_name,ctrl_portnum); } } // FD_ZERO(&readfds); // FD_SET(fd_server, &readfds); // Install_Handler(&readfds, NULL, NULL, 0.0); Handler_Add_Fd_Read(fd_server); log_debug( "%s: Listening on port %d for incoming connection", port_name, ctrl_portnum); port_mapped = true; }else{ //char* nvtmsg; size_t prompt_start_pos = 0; if(ctrl_hostname == NULL) TTCN_error("Missing mandatory parameter: CTRL_HOSTNAME"); if(ctrl_username == NULL && !ctrl_login_skipped) TTCN_error("Missing mandatory parameter: CTRL_USERNAME"); if(ctrl_password == NULL && !ctrl_login_skipped) TTCN_error("Missing mandatory parameter: CTRL_PASSWORD"); if(prompt_list.nof_prompts() == 0) TTCN_error("Missing mandatory parameter: at least one PROMPT or " "REGEX_PROMPT parameter must be provided"); prompt_list.check(port_name); nvtsock = socket( AF_INET, SOCK_STREAM, 0 ); if (nvtsock < 0) TTCN_error("Socket creation failed"); log_debug( "%s: Client socket created: %d", port_name, nvtsock); if(setsockopt(nvtsock, SOL_SOCKET, SO_REUSEADDR, (const char *)&enabled, sizeof(int)) == -1) TTCN_error("setsockopt(SO_REUSEADDR) failed"); log_debug( "%s: SO_REUSEADDR set on: %d", port_name, nvtsock); memset(&(address), 0, sizeof(address)); if(!inet_aton(ctrl_hostname,&address.sin_addr)){ log_debug( "%s: Try to resolv %s", port_name,ctrl_hostname ); struct hostent *he; if((he = gethostbyname(ctrl_hostname))==NULL) TTCN_error("Unable to resolve hostname: %s", ctrl_hostname); log_debug( "%s: Name resolved", port_name); memcpy(&address.sin_addr, he->h_addr_list[0], he->h_length); } else { log_debug( "%s: IPv4 literal conversion done", port_name); } address.sin_family = AF_INET; address.sin_port = htons(ctrl_portnum); // workaround for WinSock bug (For Cygwin) int retries = 0; log_debug( "%s: Try to connect", port_name); while (connect(nvtsock, (struct sockaddr*)&address, sizeof(address))<0){ if (errno != EADDRINUSE) { if(ctrl_detect_connection_establishment_result) { break; } else { TTCN_error( "Error connecting %s", ctrl_hostname ); break; } } if (++retries > 18) { if(ctrl_detect_connection_establishment_result) { break; } else { TTCN_error( "Error connecting %s. Address already in use.", ctrl_hostname ); break; } } log_debug( "%s: WinSock EADDRINUSE bug" " workaround: %i. retry", port_name, retries); sleep(10); } log_debug( "%s: Successfully connected to %s on TELNET port", port_name, ctrl_hostname ); isLoginSent = false; isPasswordSent = false; isDomainSent = false; isConnected = (ctrl_portnum==7)?true:false; log_debug( "%s: ----- TELNET Login Started -----", port_name); if(window_size.is_set()) { const unsigned char IAC_WILL_NAWS[] = {IAC, WILL, TELOPT_NAWS}; ::send(nvtsock, IAC_WILL_NAWS, sizeof(IAC_WILL_NAWS), 0); window_size.set_state(WSS_WILL_SENT); log_debug("%s: IAC WILL TELOPT_NAWS sent.", port_name); } #ifdef TELNET_ECHO_OPTION if(ctrl_echo) { const unsigned char IAC_DO_ECHO[] = {IAC, DO, TELOPT_ECHO}; ::send(nvtsock, IAC_DO_ECHO, sizeof(IAC_DO_ECHO), 0); log_debug("%s: IAC DO ECHO sent.", port_name); } else { const unsigned char IAC_DONT_ECHO[] = {IAC, DONT, TELOPT_ECHO}; ::send(nvtsock, IAC_DONT_ECHO, sizeof(IAC_DONT_ECHO), 0); log_debug("%s: IAC DONT ECHO sent.", port_name); } #endif struct pollfd poll_fds; poll_fds.fd=nvtsock; poll_fds.events= POLLIN | POLLPRI; while(!isConnected) { int poll_res=poll(&poll_fds,1,map_poll_timeout); if(poll_res==1){ int res=RecvClrMsg(); if(res==-2){ // ignore OOB data continue; } else { if(res < 0) { if(ctrl_detect_server_disconnected) return; else TTCN_error("*** Socket error or the server closed" " the connection."); } } } else { if(ctrl_detect_server_disconnected) { log_debug( "%s: Connection timeout during map." " Unmap the port and map it again.", port_name); if(ttcn_buf.get_len()!=0) { ttcn_buf.clear(); } Uninstall_Handler(); close( nvtsock ); nvtsock = -1; isConnected = false; incoming_message(INTEGER(0)); return; } else { TTCN_error("*** Socket timeot during map operation"); } } if(!ctrl_login_skipped) { //perform login procedure const unsigned char * ttcn_buf_data = ttcn_buf.get_data(); size_t buflen = ttcn_buf.get_len(), pos = 0; if((!isLoginSent) && (buf_strcmp("sername", ttcn_buf_data, buflen, pos) || buf_strcmp("ogin", ttcn_buf_data, buflen, pos))) { //usleep(100000UL); // 100 ms ::send(nvtsock, ctrl_username, strlen(ctrl_username), 0); if(ctrl_CRLF) ::send( nvtsock, "\r\n", 2, 0 ); else ::send( nvtsock, "\n", 1, 0 ); isLoginSent = true; ttcn_buf.clear(); log_debug("%s: user name sent.",port_name); } else if((!isPasswordSent) && buf_strcmp("assword", ttcn_buf_data, buflen, pos)) { //usleep(100000UL); // 100 ms ::send( nvtsock, ctrl_password, strlen(ctrl_password), 0); if(ctrl_CRLF) ::send( nvtsock, "\r\n", 2, 0 ); else ::send( nvtsock, "\n", 1, 0 ); isLoginSent = true; isPasswordSent = true; ttcn_buf.clear(); log_debug("%s: password sent.",port_name); } else if((!isDomainSent) && buf_strcmp("omain", ttcn_buf_data, buflen, pos)) { //usleep(100000UL); // 100 ms if(ctrl_domain == NULL) TTCN_error("%s: missing parameter " "CTRL_DOMAIN.", port_name); if(strlen(ctrl_domain))::send( nvtsock, ctrl_domain, strlen(ctrl_domain), 0); if(ctrl_CRLF) ::send( nvtsock, "\r\n", 2, 0 ); else ::send( nvtsock, "\n", 1, 0 ); isDomainSent = true; ttcn_buf.clear(); log_debug("%s: domain sent.",port_name); } else if(isPasswordSent && (isPrompt(prompt_start_pos) >= 0)) { isConnected = true; } else if((buf_strcmp("ogin incorrect", ttcn_buf_data, buflen, pos) || buf_strcmp("ogin failed", ttcn_buf_data, buflen, pos)) && (isPasswordSent)) { TTCN_error("Unable to connect to '%s' as '%s'", ctrl_hostname, ctrl_username); } } else { //login procedure is skipped if(isPrompt(prompt_start_pos)>=0) isConnected = true; } } ttcn_buf.clear(); if(ctrl_detect_connection_establishment_result) { incoming_message(INTEGER(2)); // connection establishment succeeded } if (fcntl(nvtsock, F_SETFL, O_NONBLOCK) == -1) { TTCN_error("fcntl(nvtsock, F_SETFL, O_NONBLOCK) failed: %d,%s",errno, strerror(errno)); } log_debug( "%s: ----- TELNET %sLogin Finished -----\n", port_name, ctrl_portnum==7?"ECHO":"" ); // FD_ZERO( &readfds ); // FD_SET( nvtsock, &readfds ); // Install_Handler( &readfds, NULL, NULL, 0.0 ); Handler_Add_Fd_Read(nvtsock); } } void TELNETasp__PT::user_unmap(const char *system_port) { if(ttcn_buf.get_len()!=0) { TTCN_warning("%s: Dropping partial message", port_name); log_buffer("The content of the buffer:", ttcn_buf.get_data(), ttcn_buf.get_len()); ttcn_buf.clear(); } if (server_mode){ port_mapped = false; if (nvtsock != -1){ close_connection(nvtsock); } if (fd_server != -1) close(fd_server); fd_server = -1; // FD_ZERO(&readfds); }else{ if (nvtsock != -1) { close(nvtsock); nvtsock = -1; } } Uninstall_Handler(); } void TELNETasp__PT::user_start() { } void TELNETasp__PT::user_stop() { } void TELNETasp__PT::outgoing_send(const ASP__TelnetClose& send_par){ close_connection(nvtsock); // FD_SET(fd_server, &readfds); // Install_Handler(&readfds, NULL, NULL, 0.0); Handler_Add_Fd_Read(fd_server); } void TELNETasp__PT::outgoing_send(const CHARSTRING& send_par) { log_debug( "%s: TELNETasp__PT::outgoing_send", port_name); if (server_mode) { if (!port_mapped){ TTCN_Logger::log(TTCN_WARNING, "%s: Send operation failed: the port" " is disconnected.", port_name); return; } if (!isClientLoggedIn){ TTCN_warning("%s: Send operation failed: the client has not logged in", port_name); return; } if(ctrl_server_attach_prompt){ if (send_nonblock(nvtsock, (const char*) (send_par + "\r\n" + ctrl_server_prompt), send_par.lengthof() + 2 + strlen(ctrl_server_prompt), 0 ) < 0){ if(ctrl_server_failsafe_sending){ TTCN_warning("TCP send failed"); } else{ TTCN_error("TCP send failed"); } } } else { if (send_nonblock(nvtsock, (const char*) (send_par), send_par.lengthof(), 0 ) < 0) { if(ctrl_server_failsafe_sending){ TTCN_warning("TCP send failed"); } else{ TTCN_error("TCP send failed"); } } } if(debugAllowed) { TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("%s: Message sent: ", port_name); send_par.log(); TTCN_Logger::end_event(); } } else { if(!isConnected) { log_debug( "%s: Send operation failed: the port" " is disconnected.", port_name); return; } if(ctrl_CRLF) send_nonblock( nvtsock, ( const char* ) (send_par+"\r\n"), send_par.lengthof()+2, 0 ); else send_nonblock( nvtsock, ( const char* ) (send_par+"\n"), send_par.lengthof()+1, 0 ); if(ctrl_echo==false) echobuf = send_par+"\n"; if(debugAllowed){ TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("%s: Message sent: ", port_name); send_par.log(); TTCN_Logger::end_event(); } } log_debug( "%s: TELNETasp__PT::outgoing_send end", port_name); } int TELNETasp__PT::send_nonblock(int sockfd, const char *buf, size_t len, int flags){ int ret_val=len; bool w=false; while(len){ log_debug( "%s: TELNETasp__PT::send_nonblock", port_name); int ret=::send(sockfd, buf, len, flags ); if(ret>0){ len-=ret; buf+=ret; } else { if(errno==EAGAIN){ if(!w){ TTCN_warning( "%s: TELNETasp__PT::send_nonblock, the send operation would block, waiting...", port_name); w=true; } dont_close_fd=sockfd; // Signal the event handler, that ther is a pending write operation on the fd // So the event handler won't close the conection. TTCN_Snapshot::block_for_sending((int)sockfd); if(dont_close_fd==-1){ // delayed close of the socket, the other side closed the socket meanwhile // The event handler detected the close of the fd, but didn't called the close() // Just set the dont_close_fd -1 if (server_mode){ close_connection(sockfd); } else { close(sockfd); } return -1; } dont_close_fd=-1; TTCN_warning( "%s: TELNETasp__PT::send_nonblock, next try...", port_name); } else { TTCN_warning( "%s: TELNETasp__PT::send_nonblock, fail... %d,%s ", port_name, errno, strerror(errno)); return -1; } } } if(w){ TTCN_warning( "%s: TELNETasp__PT::send_nonblock, the message finally sent", port_name); } log_debug( "%s: TELNETasp__PT::send_nonblock, data sent", port_name); return ret_val; } void TELNETasp__PT::outgoing_send(const ASP__TelnetPortParameters& send_par) { if(asp_params) delete asp_params; asp_params = new ASP__TelnetPortParameters(send_par); } void TELNETasp__PT::outgoing_send(const ASP__Get__portnum& /*send_par*/) { ASP__Portnum msg; msg.local__port__num()=ctrl_portnum; incoming_message(msg); } void TELNETasp__PT::outgoing_send(const ASP__TelnetDynamicConfig& send_par) { switch(send_par.get_selection()) { case ASP__TelnetDynamicConfig::ALT_readmode: if(send_par.readmode() == TelnetReadMode::UNBUFFERED) ctrl_readmode = READMODE_UNBUFFERED; else ctrl_readmode = READMODE_BUFFERED; break; case ASP__TelnetDynamicConfig::ALT_window__size: { const unsigned char IAC_WILL_NAWS[] = { IAC, WILL, TELOPT_NAWS }; window_size.set_width(send_par.window__size().width()); window_size.set_height(send_par.window__size().height()); if(nvtsock != -1) { switch(window_size.get_state()) { case WSS_INIT: ::send(nvtsock, IAC_WILL_NAWS, sizeof(IAC_WILL_NAWS), 0); window_size.set_state(WSS_WILL_SENT); break; // wait for server to send IAC DO TELOPT_NAWS case WSS_WILL_SENT: break; // wait for server to send IAC DO TELOPT_NAWS case WSS_AGREED: ::send(nvtsock, window_size.encode(), WINDOW_SIZE_LENGTH, 0); break; //case WSS_NOT_SET: - we did set window size so this never happens case WSS_REFUSED: default: TTCN_warning("%s: server refused window size negotiation.", port_name); break; } } else { TTCN_error("%s: error sending window size: not connected.", port_name); } break; } case ASP__TelnetDynamicConfig::ALT_echo: { #ifdef TELNET_ECHO_OPTION unsigned char cmd[3]={ IAC, 0, TELOPT_ECHO }; if(send_par.echo()==TRUE) { ctrl_echo = true; cmd[1] = DO; log_debug("%s: IAC DO ECHO sent.", port_name); } else { ctrl_echo = false; cmd[1] = DONT; log_debug("%s: IAC DONT ECHO sent.", port_name); } ::send(nvtsock, cmd, sizeof(cmd), 0); #else if(send_par.echo()==TRUE) { ctrl_echo = true; } else { ctrl_echo = false; } #endif break; } case ASP__TelnetDynamicConfig::ALT_prompt: prompt_list.set_prompt(send_par.prompt().id(), send_par.prompt().prompt(), send_par.prompt().has__wildcards()==TRUE, isRawRegexpPrompt); break; default: TTCN_error("%s: ASP_TelnetDynamicConfig has invalid selection.", port_name); break; } } void TELNETasp__PT::outgoing_send(const ASP__TelnetConnection& send_par) { user_unmap(NULL); user_map(NULL); } void TELNETasp__PT::InitStrPar(char *&par, const char* name, const char* val ) { if(name)log_debug( "%s: Reading testport parameter: " "%s = %s", port_name, name, val); if(par) free(par); par = (char*) malloc(strlen(val)+1); if(par == NULL) TTCN_error("Not enough memory."); strcpy(par, val); } int TELNETasp__PT::ProcessCmd(unsigned char * buf, int buflen) { TTCN_Buffer CMD; unsigned char *ptr = buf; int remaining_bytes = buflen; // option negotiation part while(remaining_bytes>2) { // min. length of a command is 3 #ifdef DEBUG_ProcessCmd unsigned char *cmd_start=ptr; #endif if(*ptr++ == IAC) { remaining_bytes -= 2; switch(*ptr++) { case WONT: case DONT: switch(*ptr) { case TELOPT_NAWS: window_size.set_state(WSS_REFUSED); break; /* case TELOPT_ECHO: CMD.put_c(IAC); CMD.put_c(WILL); CMD.put_c(TELOPT_ECHO); break; */ default: break; } ptr++; remaining_bytes--; break; case DO: switch(*ptr) { case TELOPT_TTYPE: CMD.put_c(IAC); ptr++; remaining_bytes--; if(ctrl_terminal_type!=NULL)CMD.put_c(WILL); else CMD.put_c(WONT); CMD.put_c(TELOPT_TTYPE); break; case TELOPT_NAWS: ptr++; remaining_bytes--; switch(window_size.get_state()) { case WSS_INIT: CMD.put_c(IAC); CMD.put_c(WILL); CMD.put_c(TELOPT_NAWS); // no break! case WSS_WILL_SENT: window_size.set_state(WSS_AGREED); // no break! case WSS_AGREED: CMD.put_s(WINDOW_SIZE_LENGTH, window_size.encode()); break; default: CMD.put_c(IAC); CMD.put_c(WONT); CMD.put_c(TELOPT_NAWS); break; } break; case TELOPT_ECHO: /* if(!ctrl_echo) { CMD.put_c(IAC); CMD.put_c(WILL); CMD.put_c(TELOPT_ECHO); ptr++; remaining_bytes--; break; }*/ default: CMD.put_c(IAC); CMD.put_c(WONT); CMD.put_c(*ptr++); remaining_bytes--; break; } break; case WILL: switch(*ptr) { case TELOPT_NAWS: CMD.put_c(IAC); switch(window_size.get_state()) { case WSS_INIT: case WSS_WILL_SENT: case WSS_AGREED: CMD.put_c(DO); break; default: CMD.put_c(DONT); break; } CMD.put_c(TELOPT_NAWS); break; #ifdef TELNET_ECHO_OPTION case TELOPT_ECHO: if(ctrl_echo) { CMD.put_c(IAC); CMD.put_c(DO); CMD.put_c(TELOPT_ECHO); } else { CMD.put_c(IAC); CMD.put_c(DONT); CMD.put_c(TELOPT_ECHO); } break; #endif default: CMD.put_c(IAC); CMD.put_c(DONT); CMD.put_c(*ptr); break; } ptr++; remaining_bytes--; break; case SB: // Subnegotiation Begin remaining_bytes--; switch(*ptr++) { case TELOPT_TTYPE: if(remaining_bytes<1) { TTCN_warning("%s: Unable to decode Terminal Type " "sub-negotiation.", port_name); break; } if(*ptr==TELQUAL_IS) { ptr++; remaining_bytes--; while(*ptr!=IAC) { // skip terminal type string if(remaining_bytes>0) { remaining_bytes--; ptr++; } else break; } } else if(*ptr==TELQUAL_SEND) { ptr++; remaining_bytes--; CMD.put_c(IAC); CMD.put_c(SB); CMD.put_c(TELOPT_TTYPE); CMD.put_c(TELQUAL_IS); CMD.put_s(strlen(ctrl_terminal_type), (const unsigned char *)ctrl_terminal_type); CMD.put_c(IAC); CMD.put_c(SE); } else { ptr++; remaining_bytes--; log_debug( "%s: octet after IAC SB " "TERMINAL-TYPE is 0x%02x in option negotiation.", port_name, *ptr); } break; case TELOPT_NAWS: // Window Size - in case server sends this ptr += 4; remaining_bytes -= 4; break; default: log_debug("%s: Telnet option not " "handled: 0x%02x.", port_name, *ptr); ptr++; remaining_bytes--; while(*ptr!=IAC) { // skip until IAC if(remaining_bytes>0) { remaining_bytes--; ptr++; } else break; } break; } ptr += 2; // skip IAC SE remaining_bytes -= 2; break; default: log_debug(" %s: Telnet Command not handled: " "0x%02x", port_name, *ptr); break; } } else { ptr--; break;} #ifdef DEBUG_ProcessCmd if(debugAllowed) { TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("%s: processed command: ", port_name); bool ttype=false; while(cmd_start= TELCMD_FIRST) TTCN_Logger::log_event("%s ",TELCMD(*cmd_start)); else if(*cmd_start <= TELOPT_LAST) { if(ttype && (*cmd_start)<2) TTCN_Logger::log_event_str((*cmd_start)?"SEND ":"IS "); else TTCN_Logger::log_event("%s ", TELOPT(*cmd_start)); } else TTCN_Logger::log_event("%d ", *cmd_start); cmd_start++; } TTCN_Logger::end_event(); } #endif } if(CMD.get_len() > 0) { CMD.rewind(); ::send( nvtsock, CMD.get_read_data(), CMD.get_read_len(), 0 ); if(debugAllowed) { #ifdef DEBUG_ProcessCmd if(TTCN_Logger::log_this_event(TTCN_DEBUG)) { TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("%s: command sent:", port_name); bool ttype=false, subcmd=false, naws=false; const unsigned char *cmd_ptr = CMD.get_read_data(); unsigned int cmd_len=CMD.get_read_len(); for(unsigned int i=0;i= TELCMD_FIRST) TTCN_Logger::log_event("%s ",TELCMD(*cmd_ptr)); else if(ttype) { switch(*cmd_ptr) { case 0: TTCN_Logger::log_event_str("IS "); break; case 1: TTCN_Logger::log_event_str("SEND "); break; default: if(*cmd_ptr>' ' && *cmd_ptr<128) TTCN_Logger::log_event("\"%c\" ",*cmd_ptr); else TTCN_Logger::log_event("%d ",*cmd_ptr); } } else if(naws) TTCN_Logger::log_event("%d ", *cmd_ptr); else if(*cmd_ptr <= TELOPT_LAST) TTCN_Logger::log_event("%s ", TELOPT(*cmd_ptr)); else TTCN_Logger::log_event("%d ", *cmd_ptr); if(*cmd_ptr==TELOPT_NAWS)naws=true; else if(*cmd_ptr==TELOPT_TTYPE)ttype=true; cmd_ptr++; } TTCN_Logger::end_event(); } #else log_buffer("ProcessCmd: command sent:", CMD.get_read_data(), CMD.get_read_len()); #endif } } if(remaining_bytes != buflen) { ttcn_buf.set_pos(buflen-remaining_bytes); ttcn_buf.cut(); memmove(buf, ptr, remaining_bytes); buflen = remaining_bytes; } return buflen; } int TELNETasp__PT::isPrompt(size_t &pos) { return prompt_list.findPrompt(pos, ttcn_buf.get_data(), ttcn_buf.get_len()); } int TELNETasp__PT::RecvClrMsg() { unsigned char inbuf[BUFFER_SIZE]; errno=0; int end_len = BUFFER_SIZE, len = recv(nvtsock, inbuf , end_len, MSG_DONTWAIT); if(len<0 && errno == EAGAIN){ // ignore OOB data. recv(nvtsock, inbuf , end_len, MSG_DONTWAIT|MSG_OOB); return -2; } if(len>0){ log_debug( "%s: ********************** NEW MESSAGE" " RECEIVED **********************", port_name); log_buffer("RecvClrMsg received message:", inbuf, len); } else if (len==0){ log_debug("%s: ******** Connection is closed " "by peer.",port_name); } else { log_debug("%s: ******** Error occured during reading " "socket. errno value: %d",port_name,errno); } if (len < 1) { if(ctrl_detect_server_disconnected) { log_debug( "%s: Connection is broken." " Unmap the port and map it again.", port_name); if(ttcn_buf.get_len()!=0) { ttcn_buf.clear(); } Uninstall_Handler(); nvtsock = -1; isConnected = false; incoming_message(INTEGER(0)); if(dont_close_fd==nvtsock) { dont_close_fd=-1; } else { close( nvtsock ); } } return -1; } len = ProcessCmd(inbuf, len); for(int i=0;is2_len) { return false; } for(int i=0;i<(int)(s2_len-s1_len+1); ) { size_t j = 0; while((unsigned char)s1[j] == s2[i+j]) { j++; } if(j==s1_len) { pos = i; return true; } i+=j>0?j:1; } return false; } void TELNETasp__PT::log_debug(const char *fmt, ...) { if(debugAllowed) { TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("TELNET test port (%s): ", get_name()); va_list ap; va_start(ap, fmt); TTCN_Logger::log_event_va_list(fmt, ap); va_end(ap); TTCN_Logger::end_event(); } } void TELNETasp__PT::log_buffer(const char * logmsg, const unsigned char * buf, size_t buflen) { if(debugAllowed) { log_debug( "%s: %s: ", port_name, logmsg); for(size_t j=0;jlog(); TTCN_Logger::end_event(); if(asp_params->ctrl__hostname().ispresent()==TRUE) InitStrPar(ctrl_hostname, NULL, (CHARSTRING)asp_params->ctrl__hostname()); if(asp_params->ctrl__portnum().ispresent()==TRUE) ctrl_portnum = (INTEGER)asp_params->ctrl__portnum(); if(asp_params->ctrl__username().ispresent()==TRUE) InitStrPar(ctrl_username, NULL, (CHARSTRING)asp_params->ctrl__username()); if(asp_params->ctrl__password().ispresent()==TRUE) InitStrPar(ctrl_password, NULL, (CHARSTRING)asp_params->ctrl__password()); if(asp_params->ctrl__domain().ispresent()==TRUE) InitStrPar(ctrl_domain, NULL, (CHARSTRING)asp_params->ctrl__domain()); if(asp_params->ctrl__readmode().ispresent()==TRUE) { if(((TelnetReadMode)asp_params->ctrl__readmode())== TelnetReadMode::UNBUFFERED) { ctrl_readmode = READMODE_UNBUFFERED; } else { ctrl_readmode = READMODE_BUFFERED; } } if(asp_params->ctrl__login__skipped().ispresent()==TRUE) { if((BOOLEAN)asp_params->ctrl__login__skipped() == TRUE) ctrl_login_skipped = true; else ctrl_login_skipped = false; } if(asp_params->ctrl__detect__server__disconnected().ispresent()==TRUE) { if((BOOLEAN)asp_params->ctrl__detect__server__disconnected() == TRUE) ctrl_detect_server_disconnected = true; else ctrl_detect_server_disconnected = false; } if(asp_params->prompts().ispresent()==TRUE && ((TelnetPrompts)asp_params->prompts()).size_of() > 0) { prompt_list.clear(); const TelnetPrompts& asp_prompts = (TelnetPrompts)asp_params->prompts(); unsigned int nof_prompts = asp_prompts.size_of(); for(unsigned int i=0;ictrl__terminal__type().ispresent()==TRUE) InitStrPar(ctrl_terminal_type, NULL, (CHARSTRING)asp_params->ctrl__terminal__type()); if(asp_params->ctrl__echo().ispresent()==TRUE) { if((BOOLEAN)asp_params->ctrl__echo() == TRUE) ctrl_echo = true; else ctrl_echo = false; } if(asp_params->ctrl__CRLF().ispresent()==TRUE) { if((BOOLEAN)asp_params->ctrl__CRLF() == TRUE) ctrl_CRLF = true; else ctrl_CRLF = false; } if(asp_params->ctrl__window__size().ispresent()==TRUE) { window_size.set_width(((TelnetWindowSize) asp_params->ctrl__window__size()).width()); window_size.set_height(((TelnetWindowSize) asp_params->ctrl__window__size()).height()); } delete asp_params; asp_params = NULL; } void TELNETasp__PT::reset_configuration() { free(ctrl_hostname); ctrl_hostname = NULL; ctrl_portnum = 0; free(ctrl_username); ctrl_username = NULL; free(ctrl_password); ctrl_password = NULL; free(ctrl_domain); ctrl_domain = NULL; ctrl_readmode = READMODE_BUFFERED; prompt_list.clear(); ctrl_login_skipped = false; ctrl_detect_server_disconnected = false; free(ctrl_terminal_type); ctrl_terminal_type = NULL; ctrl_echo = false; ctrl_CRLF = false; window_size.reset(); delete asp_params; asp_params = NULL; free(ctrl_username_client); ctrl_username_client = NULL; free(ctrl_password_client); ctrl_password_client = NULL; free(ctrl_server_prompt); ctrl_server_prompt = NULL; server_mode_def = false; isClientLoggedIn = false; pass_prompt_send = false; login_incorrect = false; free(ctrl_password_prompt); ctrl_password_prompt = NULL; free(ctrl_loginname_prompt); ctrl_loginname_prompt = NULL; debugAllowed = false; } void TELNETasp__PT::recv_msg_from_client(int &fd){ unsigned char inbuf[BUFFER_SIZE]; int length; log_debug("%s: Receive message from client", port_name); length = recv(fd, inbuf, BUFFER_SIZE, O_NONBLOCK); switch (length){ case -1:{ log_debug("%s: Error reading from file descriptor %d. Errno = %d", port_name, fd, errno); errno = 0; // close_connection(fd); // nvtsock=-1; // FD_SET(fd_server, &readfds); // Install_Handler(&readfds, NULL, NULL, 0.0); Handler_Add_Fd_Read(fd_server); if(ctrl_detect_client_disconnected){ //notify the server that the client disonnected. incoming_message(INTEGER(3)); } if(dont_close_fd==fd) { dont_close_fd=-1; return; } close_connection(fd); break; } case 0:{ log_debug("Client closed connection (filedescriptor: %d)", fd); // close_connection(fd); // FD_SET(fd_server, &readfds); // Install_Handler(&readfds, NULL, NULL, 0.0); // nvtsock=-1; Handler_Add_Fd_Read(fd_server); if(ctrl_detect_client_disconnected){ //notify the server that the client disonnected. incoming_message(INTEGER(3)); } if(dont_close_fd==fd) { dont_close_fd=-1; return; } close_connection(fd); break; } default:{ int new_length; bool delimiter_came = false; if ( (new_length = ProcessNoCmd(inbuf, length)) == 0) return; if(debugAllowed) { TTCN_logger.log(TTCN_DEBUG,"%s: ------------------------ Logging incoming messages -----------------------------", port_name); TTCN_logger.log(TTCN_DEBUG," (characters after the first \\n or \\r character will be discarded)"); log_buffer("Message received from client: (hexstring fromat)", inbuf, length); CHARSTRING cc = CHARSTRING((int)length, (const char*)inbuf); TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("%s: Message received from client: (charstring format)\n", port_name); cc.log(); TTCN_Logger::end_event(); TTCN_logger.log(TTCN_DEBUG,"%s ------------------------ End logging -----------------------------\n", port_name); } if (!isClientLoggedIn){ int pos; for (int i = 0; i < new_length; i++){ if ( (inbuf[i] == '\n') || (inbuf[i] == '\r')){ delimiter_came = true; pos = i; break; } } if (delimiter_came) ttcn_buf.put_s(pos+1, inbuf); else ttcn_buf.put_s(new_length, inbuf); if(debugAllowed) { TTCN_logger.log(TTCN_DEBUG,"%s: ------------------------ Logging the incoming buffer -----------------------------", port_name); log_buffer("The content of the incoming buffer: (hexstring fromat)", inbuf, length); CHARSTRING cc = CHARSTRING((int)ttcn_buf.get_len(), (const char*)ttcn_buf.get_data()); TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("%s: The content of the incoming buffert: (charstring format)\n", port_name); cc.log(); TTCN_Logger::end_event(); TTCN_logger.log(TTCN_DEBUG,"%s ------------------------ End logging -----------------------------\n", port_name); } if (delimiter_came && !pass_prompt_send){ if (!check((const char *)ctrl_username_client, ttcn_buf.get_data(), ttcn_buf.get_len() ) ){ login_incorrect = true; } ttcn_buf.set_pos(ttcn_buf.get_len()); if (::send(fd, "\r\n", 2, 0) < 0 ){ if(ctrl_server_failsafe_sending){ TTCN_warning("TCP send failed"); goto conn_setup_client_disc; } else{ TTCN_error("TCP send failed"); } } if (::send(fd, ctrl_password_prompt, strlen(ctrl_password_prompt), 0) < 0 ){ if(ctrl_server_failsafe_sending){ TTCN_warning("TCP send failed"); goto conn_setup_client_disc; } else{ TTCN_error("TCP send failed"); } } pass_prompt_send = true; } else if (delimiter_came && pass_prompt_send){ int pos = ttcn_buf.get_pos(); if (login_incorrect || !check((const char *)ctrl_password_client, ttcn_buf.get_data()+pos, ttcn_buf.get_len()-pos) ) { int len = ttcn_buf.get_len(); const char *data = (const char*)ttcn_buf.get_data(); CHARSTRING cc1( pos - 1, data); CHARSTRING cc2(len - pos - 1, data + pos); TTCN_Logger::begin_event(TTCN_ERROR); TTCN_Logger::log_event("%s: ---------------------------Login incorrect------------------------\n", port_name); TTCN_Logger::log_event("Username: "); cc1.log(); TTCN_Logger::log_event("\nPassword: "); cc2.log(); if (::send(nvtsock, "Login incorrect\r\n", 17, 0) < 0) TTCN_error("TCP send failed"); TTCN_Logger::end_event(); TTCN_error("Login incorrect!"); } isClientLoggedIn = true; if (fcntl(nvtsock, F_SETFL, O_NONBLOCK) == -1) { TTCN_error("fcntl(nvtsock, F_SETFL, O_NONBLOCK) failed: %d,%s",errno, strerror(errno)); } incoming_message(INTEGER(1)); ttcn_buf.clear(); const char *welcome = "Welcome\r\n"; if (::send(fd, welcome, strlen(welcome), 0) < 0){ if(ctrl_server_failsafe_sending){ TTCN_warning("TCP send failed"); goto conn_setup_client_disc; } else{ TTCN_error("TCP send failed"); } } if (::send(fd, ctrl_server_prompt, strlen(ctrl_server_prompt),0) < 0){ if(ctrl_server_failsafe_sending){ TTCN_warning("TCP send failed"); goto conn_setup_client_disc; } else{ TTCN_error("TCP send failed"); } } } break; } ttcn_buf.put_s(new_length,inbuf); if(debugAllowed) { TTCN_logger.log(TTCN_DEBUG,"%s: ------------------------ Logging the incoming buffer -----------------------------", port_name); log_buffer("The content of the incoming buffer: (hexstring fromat)", inbuf, length); CHARSTRING cc = CHARSTRING((int)ttcn_buf.get_len(), (const char*)ttcn_buf.get_data()); TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("%s: The content of the incoming buffert: (charstring format)\n", port_name); cc.log(); TTCN_Logger::end_event(); TTCN_logger.log(TTCN_DEBUG,"%s ------------------------ End logging -----------------------------\n", port_name); } int i,len; const unsigned char *data; for(;;){ data = ttcn_buf.get_data(); len = ttcn_buf.get_len(); for (i = 0; i < len ; i++){ if ( (data[i] == '\n' ) || (data[i] == '\r') ){ incoming_message(CHARSTRING(i, (const char*)data )); break; } } if (i == len) break; if (i < len - 1 && data[i] == '\r' && ( data[i+1] == '\0' || data[i+1] == '\n') ) i++; ttcn_buf.set_pos(i+1); ttcn_buf.cut(); if (i == len) break; }; } } return; conn_setup_client_disc: // Something went wrong during the connection set up // go back listening and close the socket close_connection(fd); Handler_Add_Fd_Read(fd_server); return; } int TELNETasp__PT::ProcessNoCmd(unsigned char * buf, int buflen) { unsigned char CMD[1024]; int cmd_len = 0, i; log_debug("Processing commands"); // option negotiation part for ( i = 0; i+2 < buflen; i += 3 ) { if(buf[i] == IAC ) { switch(buf[i+1] ) { case WONT: case DONT: break; case DO: CMD[cmd_len++] = IAC; CMD[cmd_len++] = WONT; CMD[cmd_len++] = buf[i+2]; break; case WILL: CMD[cmd_len++] = IAC; CMD[cmd_len++] = DONT; CMD[cmd_len++] = buf[i+2]; break; default: log_debug("%s: Telnet Command not handled: 0x%02x", port_name, buf[i+1]); } } else break; } if(i!=0) { log_debug("Sending commands"); ::send( nvtsock, (const char*)CMD, cmd_len, 0 ); ttcn_buf.set_pos(i); ttcn_buf.cut(); log_buffer("ProcessCmd: command sent:", CMD, cmd_len); memmove(buf, &buf[i], buflen-i); buflen -= i; } return buflen; } bool TELNETasp__PT::check(const char * s1, const unsigned char * s2, int s2_len){ int s1_len = strlen(s1); if (s1_len > s2_len){return false;} for (int i = 0; i< s1_len; i++){ if (s1[i] != s2[i] ) return false; } return s2[s1_len] == '\n' || s2[s1_len] == '\r' || s2[s1_len] == '\0'; } INTEGER FindString(const CHARSTRING& msg_ch, const CHARSTRING& pattern_ch) { const char* p; int n = 0, x = 0; const char* msg = ( const char* ) msg_ch; const char* pattern = ( const char* ) pattern_ch; int plen = strlen( pattern ); int mlen = strlen( msg ); while( x < mlen + plen - 1 ) { if( ( p = strstr( &msg[x], pattern ) ) == NULL ) break; else { x = ( int ) ( p - msg ) + plen; n++; } } return n; } Window_Size::Window_Size(const char *p_port_name) : my_state(WSS_NOT_SET), width(-1), height(-1), ws_debugAllowed(false) { if(p_port_name==NULL) p_port_name = ""; port_name = new char[strlen(p_port_name) + 1]; strcpy(port_name, p_port_name); } Window_Size::~Window_Size() { delete []port_name; } void Window_Size::log_debug(const char *fmt, ...) { if(ws_debugAllowed) { TTCN_Logger::begin_event(TTCN_DEBUG); va_list ap; va_start(ap, fmt); TTCN_Logger::log_event_va_list(fmt, ap); va_end(ap); TTCN_Logger::end_event(); } } void Window_Size::set_debug(bool debug_enabled) { ws_debugAllowed = debug_enabled; } void Window_Size::set_state(WindowSize_state_t new_state) { if(!is_set()) my_state = WSS_NOT_SET; else switch(new_state) { case WSS_INIT: log_debug("Window_Size::set_state(): can't set " "state to WSS_INIT."); break; case WSS_WILL_SENT: if(my_state == WSS_INIT) my_state = WSS_WILL_SENT; else log_debug("Window_Size::set_state(): can't set " "state to WSS_WILL_SENT."); break; case WSS_AGREED: switch(my_state) { case WSS_INIT: case WSS_WILL_SENT: case WSS_AGREED: my_state = WSS_AGREED; break; default: log_debug("Window_Size::set_state(): can't set " "state to WSS_AGREED."); break; } break; case WSS_REFUSED: if(my_state != WSS_REFUSED && is_set()) TTCN_warning("%s: server " "refused window size negotiation.", port_name); my_state = WSS_REFUSED; break; case WSS_NOT_SET: TTCN_error("Window_Size::set_state(): state shouldn't be set to " "WSS_NOT_SET explicitly."); break; default: TTCN_error("Window_Size::set_state(): unknown state."); break; } } void Window_Size::set_width(int w) { if(w<=0||w>65535) TTCN_error("%s: width of window size should be greater " "than 0 and less than 65536.", port_name); width = w; if(height > 0 && my_state == WSS_NOT_SET) my_state = WSS_INIT; } void Window_Size::set_height(int h) { if(h<=0||h>65535) TTCN_error("%s: height of window size should be greater " "than 0 and less than 65536.", port_name); height = h; if(width > 0 && my_state == WSS_NOT_SET) my_state = WSS_INIT; } const unsigned char *Window_Size::encode() const { static unsigned char pdu[] = { IAC, SB, TELOPT_NAWS, 0, 80, 0, 24, IAC, SE }; if(!is_set()) TTCN_error("%s: sending window size option without window " "size being set.", port_name); pdu[3] = width >> 8; pdu[4] = width; pdu[5] = height >> 8; pdu[6] = height; return pdu; } Regex_Prompt::Regex_Prompt(const char *p_pattern, bool debug_enabled, bool raw_prompt) { rp_debugAllowed = debug_enabled; char *posix_str=NULL; if(raw_prompt){ posix_str = mcopystr(p_pattern); } else { CHARSTRING cstr("(*)("); // string before prompt cstr = cstr + p_pattern; // prompt cstr = cstr + ")(*)"; // string after prompt posix_str = TTCN_pattern_to_regexp_telnet(cstr); } if(posix_str == NULL) TTCN_error("Cannot convert pattern \"%s\" to " "POSIX-equivalent.", p_pattern); // posix_str[strlen(posix_str)-1] = '\0'; // remove trailing "$" int ret_val=regcomp(&posix_regexp, posix_str, REG_EXTENDED); // +1 -> no ^ log_debug("Translated pattern (%zd subexpressions): %s",posix_regexp.re_nsub, posix_str); Free(posix_str); if(ret_val!=0) { char err[512]; regerror(ret_val, &posix_regexp, err, sizeof(err)); regfree(&posix_regexp); TTCN_error("Function regcomp() failed while setting regexp pattern " "\"%s\" as prompt: %s", p_pattern, err); } } Regex_Prompt::~Regex_Prompt() { regfree(&posix_regexp); } void Regex_Prompt::log_debug(const char *fmt, ...) { if(rp_debugAllowed) { TTCN_Logger::begin_event(TTCN_DEBUG); va_list ap; va_start(ap, fmt); TTCN_Logger::log_event_va_list(fmt, ap); va_end(ap); TTCN_Logger::end_event(); } } Regex_Prompt_MatchResult Regex_Prompt::match(const char *msg) { Regex_Prompt_MatchResult ret_val; regmatch_t pmatch[4]; int result = regexec(&posix_regexp, msg, 4, pmatch, 0); /* for (int i=0;i<4;i++) log_debug( "result: %d, start: %u, end: %u", result, pmatch[i].rm_so, pmatch[i].rm_eo);*/ if(result == 0) { ret_val.match = true; ret_val.start = pmatch[2].rm_so; ret_val.end = pmatch[2].rm_eo; } else if(result == REG_NOMATCH) { ret_val.match = false; ret_val.start = 0; ret_val.end = 0; } else { char err[512]; regerror(result, &posix_regexp, err, sizeof(err)); TTCN_error("Error matching regexp prompt: %s", err); } return ret_val; } Prompt_List::~Prompt_List() { clear(); } void Prompt_List::log_debug(const char *fmt, ...) { if(pl_debugAllowed) { TTCN_Logger::begin_event(TTCN_DEBUG); va_list ap; va_start(ap, fmt); TTCN_Logger::log_event_va_list(fmt, ap); va_end(ap); TTCN_Logger::end_event(); } } void Prompt_List::set_debug(bool debug_enabled) { pl_debugAllowed = debug_enabled; } void Prompt_List::set_prompt(unsigned int p_id, const char *p_prompt, bool p_is_regex, bool raw_prompt) { size_t index; if( !id_to_index(p_id, index) ) { index = n_elems++; if(n_elems==1) elems = (prompt_elem**)malloc(sizeof(prompt_elem*)); else elems = (prompt_elem**)realloc(elems, n_elems *sizeof(prompt_elem*)); if(!elems) TTCN_error("Not enough memory."); } else { if(elems[index]->is_regex) delete elems[index]->regex_prompt; else delete [](elems[index]->prompt); delete elems[index]; } elems[index] = new prompt_elem; elems[index]->id = p_id; elems[index]->is_regex = p_is_regex; if(p_is_regex) { elems[index]->regex_prompt = new Regex_Prompt(p_prompt,pl_debugAllowed,raw_prompt); } else { elems[index]->prompt = new char[strlen(p_prompt)+1]; strcpy(elems[index]->prompt, p_prompt); } } void Prompt_List::check(const char *warning_prefix) { if(n_elems) { for(unsigned int i=0;iis_regex) continue; const char *pi = elems[i]->prompt; for(unsigned int j=i+1;jis_regex) continue; const char *pj = elems[j]->prompt; if(!strcmp(pi, pj)) { TTCN_warning("Duplicated prompt string '%s'", pi); break; } else if(strstr(pi, pj)) { TTCN_warning("Using prompt '%s' that is a substring of" " prompt '%s' might cause problems", pj, pi); break; } else if(strstr(pj, pi)) { TTCN_warning("Using prompt '%s' that is a substring of" " prompt '%s' might cause problems", pi, pj); break; } } } } } void Prompt_List::clear() { if(elems) { for(size_t i=0;iis_regex) delete elems[i]->regex_prompt; else delete [](elems[i]->prompt); delete elems[i]; } free(elems); elems = NULL; } n_elems = 0; } int Prompt_List::findPrompt(size_t &pos, const unsigned char *bufptr, size_t buflen) const { char *buf_asciiz = NULL; for(size_t i=0;iis_regex == false) { size_t prompt_len = strlen(elems[i]->prompt); if(prompt_len<=buflen) { if(strncmp(elems[i]->prompt, (const char *) (bufptr+buflen-prompt_len), prompt_len)==0) { pos = buflen-prompt_len; if(buf_asciiz) delete []buf_asciiz; return prompt_len; } } } else { if(!buf_asciiz) { buf_asciiz = new char[buflen+1]; memcpy(buf_asciiz, bufptr, buflen); buf_asciiz[buflen] = '\0'; } Regex_Prompt_MatchResult result = elems[i]->regex_prompt->match(buf_asciiz); if(result.match) { pos = result.start; delete []buf_asciiz; return result.end - result.start; } } } if(buf_asciiz) delete []buf_asciiz; return -1; } bool Prompt_List::id_to_index(unsigned int p_id, size_t &index) const { for(index=0; indexid == p_id) return true; return false; } void TELNETasp__PT::close_connection(int& fd){ if (fd < 0){ log_debug("close_connection(): file descriptor is negative (%d)", fd); return; } // FD_CLR(fd, &readfds); // Install_Handler(&readfds, NULL, NULL, 0.0); Handler_Remove_Fd_Read(fd); close(fd); isClientLoggedIn = false; pass_prompt_send = false; login_incorrect = false; fd = -1; } }