diff options
author | Alexander Smirnov <alex@ydb.tech> | 2024-10-16 12:11:24 +0000 |
---|---|---|
committer | Alexander Smirnov <alex@ydb.tech> | 2024-10-16 12:11:24 +0000 |
commit | 40811e93f3fdf9342a9295369994012420fac548 (patch) | |
tree | a8d85e094a9c21e10aa250f537c101fc2016a049 /contrib/libs/curl/lib/telnet.c | |
parent | 30ebe5357bb143648c6be4d151ecd4944af81ada (diff) | |
parent | 28a0c4a9f297064538a018c512cd9bbd00a1a35d (diff) | |
download | ydb-40811e93f3fdf9342a9295369994012420fac548.tar.gz |
Merge branch 'rightlib' into mergelibs-241016-1210
Diffstat (limited to 'contrib/libs/curl/lib/telnet.c')
-rw-r--r-- | contrib/libs/curl/lib/telnet.c | 157 |
1 files changed, 74 insertions, 83 deletions
diff --git a/contrib/libs/curl/lib/telnet.c b/contrib/libs/curl/lib/telnet.c index 8cd19b1b09..836e255c9d 100644 --- a/contrib/libs/curl/lib/telnet.c +++ b/contrib/libs/curl/lib/telnet.c @@ -160,7 +160,6 @@ struct TELNET { unsigned short subopt_wsy; /* Set with suboption NAWS */ TelnetReceive telrcv_state; struct curl_slist *telnet_vars; /* Environment variables */ - struct dynbuf out; /* output buffer */ /* suboptions */ unsigned char subbuffer[SUBBUFSIZE]; @@ -173,7 +172,7 @@ struct TELNET { */ const struct Curl_handler Curl_handler_telnet = { - "telnet", /* scheme */ + "TELNET", /* scheme */ ZERO_NULL, /* setup_connection */ telnet_do, /* do_it */ telnet_done, /* done */ @@ -186,8 +185,7 @@ const struct Curl_handler Curl_handler_telnet = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ - ZERO_NULL, /* write_resp */ - ZERO_NULL, /* write_resp_hd */ + ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_TELNET, /* defport */ @@ -206,7 +204,6 @@ CURLcode init_telnet(struct Curl_easy *data) if(!tn) return CURLE_OUT_OF_MEMORY; - Curl_dyn_init(&tn->out, 0xffff); data->req.p.telnet = tn; /* make us known */ tn->telrcv_state = CURL_TS_DATA; @@ -798,14 +795,12 @@ static CURLcode check_telnet_options(struct Curl_easy *data) struct TELNET *tn = data->req.p.telnet; CURLcode result = CURLE_OK; - /* Add the username as an environment variable if it + /* Add the user name as an environment variable if it was given on the command line */ if(data->state.aptr.user) { char buffer[256]; - if(str_is_nonascii(data->conn->user)) { - DEBUGF(infof(data, "set a non ASCII username in telnet")); + if(str_is_nonascii(data->conn->user)) return CURLE_BAD_FUNCTION_ARGUMENT; - } msnprintf(buffer, sizeof(buffer), "USER,%s", data->conn->user); beg = curl_slist_append(tn->telnet_vars, buffer); if(!beg) { @@ -831,27 +826,23 @@ static CURLcode check_telnet_options(struct Curl_easy *data) case 5: /* Terminal type */ if(strncasecompare(option, "TTYPE", 5)) { - size_t l = strlen(arg); - if(l < sizeof(tn->subopt_ttype)) { - strcpy(tn->subopt_ttype, arg); - tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES; - break; - } + strncpy(tn->subopt_ttype, arg, 31); + tn->subopt_ttype[31] = 0; /* String termination */ + tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES; } - result = CURLE_UNKNOWN_OPTION; + else + result = CURLE_UNKNOWN_OPTION; break; case 8: /* Display variable */ if(strncasecompare(option, "XDISPLOC", 8)) { - size_t l = strlen(arg); - if(l < sizeof(tn->subopt_xdisploc)) { - strcpy(tn->subopt_xdisploc, arg); - tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES; - break; - } + strncpy(tn->subopt_xdisploc, arg, 127); + tn->subopt_xdisploc[127] = 0; /* String termination */ + tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES; } - result = CURLE_UNKNOWN_OPTION; + else + result = CURLE_UNKNOWN_OPTION; break; case 7: @@ -1191,12 +1182,12 @@ process_iac: if(c != CURL_SE) { if(c != CURL_IAC) { /* - * This is an error. We only expect to get "IAC IAC" or "IAC SE". - * Several things may have happened. An IAC was not doubled, the + * This is an error. We only expect to get "IAC IAC" or "IAC SE". + * Several things may have happened. An IAC was not doubled, the * IAC SE was left off, or another option got inserted into the - * suboption are all possibilities. If we assume that the IAC was + * suboption are all possibilities. If we assume that the IAC was * not doubled, and really the IAC SE was left off, we could get - * into an infinite loop here. So, instead, we terminate the + * into an infinite loop here. So, instead, we terminate the * suboption, and process the partial suboption if we can. */ CURL_SB_ACCUM(tn, CURL_IAC); @@ -1232,37 +1223,37 @@ process_iac: static CURLcode send_telnet_data(struct Curl_easy *data, char *buffer, ssize_t nread) { - size_t i, outlen; - unsigned char *outbuf; + ssize_t escapes, i, outlen; + unsigned char *outbuf = NULL; CURLcode result = CURLE_OK; - size_t bytes_written; - size_t total_written = 0; + ssize_t bytes_written, total_written; struct connectdata *conn = data->conn; - struct TELNET *tn = data->req.p.telnet; - DEBUGASSERT(tn); - DEBUGASSERT(nread > 0); - if(nread < 0) - return CURLE_TOO_LARGE; + /* Determine size of new buffer after escaping */ + escapes = 0; + for(i = 0; i < nread; i++) + if((unsigned char)buffer[i] == CURL_IAC) + escapes++; + outlen = nread + escapes; - if(memchr(buffer, CURL_IAC, nread)) { - /* only use the escape buffer when necessary */ - Curl_dyn_reset(&tn->out); + if(outlen == nread) + outbuf = (unsigned char *)buffer; + else { + ssize_t j; + outbuf = malloc(nread + escapes + 1); + if(!outbuf) + return CURLE_OUT_OF_MEMORY; - for(i = 0; i < (size_t)nread && !result; i++) { - result = Curl_dyn_addn(&tn->out, &buffer[i], 1); - if(!result && ((unsigned char)buffer[i] == CURL_IAC)) - /* IAC is FF in hex */ - result = Curl_dyn_addn(&tn->out, "\xff", 1); + j = 0; + for(i = 0; i < nread; i++) { + outbuf[j++] = (unsigned char)buffer[i]; + if((unsigned char)buffer[i] == CURL_IAC) + outbuf[j++] = CURL_IAC; } - - outlen = Curl_dyn_len(&tn->out); - outbuf = Curl_dyn_uptr(&tn->out); - } - else { - outlen = (size_t)nread; - outbuf = (unsigned char *)buffer; + outbuf[j] = '\0'; } + + total_written = 0; while(!result && total_written < outlen) { /* Make sure socket is writable to avoid EWOULDBLOCK condition */ struct pollfd pfd[1]; @@ -1275,13 +1266,19 @@ static CURLcode send_telnet_data(struct Curl_easy *data, break; default: /* write! */ bytes_written = 0; - result = Curl_xfer_send(data, outbuf + total_written, - outlen - total_written, FALSE, &bytes_written); + result = Curl_nwrite(data, FIRSTSOCKET, + outbuf + total_written, + outlen - total_written, + &bytes_written); total_written += bytes_written; break; } } + /* Free malloc copy if escaped */ + if(outbuf != (unsigned char *)buffer) + free(outbuf); + return result; } @@ -1297,7 +1294,6 @@ static CURLcode telnet_done(struct Curl_easy *data, curl_slist_free_all(tn->telnet_vars); tn->telnet_vars = NULL; - Curl_dyn_free(&tn->out); return CURLE_OK; } @@ -1325,7 +1321,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) ssize_t nread; struct curltime now; bool keepon = TRUE; - char buffer[4*1024]; + char *buf = data->state.buffer; struct TELNET *tn; *done = TRUE; /* unconditionally */ @@ -1342,7 +1338,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) #ifdef USE_WINSOCK /* We want to wait for both stdin and the socket. Since - ** the select() function in Winsock only works on sockets + ** the select() function in winsock only works on sockets ** we have to use the WaitForMultipleObjects() call. */ @@ -1353,7 +1349,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) return CURLE_FAILED_INIT; } - /* Tell Winsock what events we want to listen to */ + /* Tell winsock what events we want to listen to */ if(WSAEventSelect(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) { WSACloseEvent(event_handle); return CURLE_OK; @@ -1370,7 +1366,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) else use the old WaitForMultipleObjects() way */ if(GetFileType(stdin_handle) == FILE_TYPE_PIPE || data->set.is_fread_set) { - /* Do not wait for stdin_handle, just wait for event_handle */ + /* Don't wait for stdin_handle, just wait for event_handle */ obj_count = 1; /* Check stdin_handle per 100 milliseconds */ wait_timeout = 100; @@ -1382,7 +1378,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) /* Keep on listening and act on events */ while(keepon) { - const DWORD buf_size = (DWORD)sizeof(buffer); + const DWORD buf_size = (DWORD)data->set.buffer_size; DWORD waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout); switch(waitret) { @@ -1393,7 +1389,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) if(data->set.is_fread_set) { size_t n; /* read from user-supplied method */ - n = data->state.fread_func(buffer, 1, buf_size, data->state.in); + n = data->state.fread_func(buf, 1, buf_size, data->state.in); if(n == CURL_READFUNC_ABORT) { keepon = FALSE; result = CURLE_READ_ERROR; @@ -1421,7 +1417,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) if(!readfile_read) break; - if(!ReadFile(stdin_handle, buffer, buf_size, + if(!ReadFile(stdin_handle, buf, buf_size, &readfile_read, NULL)) { keepon = FALSE; result = CURLE_READ_ERROR; @@ -1429,7 +1425,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) } } - result = send_telnet_data(data, buffer, readfile_read); + result = send_telnet_data(data, buf, readfile_read); if(result) { keepon = FALSE; break; @@ -1440,14 +1436,14 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) case WAIT_OBJECT_0 + 1: { - if(!ReadFile(stdin_handle, buffer, buf_size, + if(!ReadFile(stdin_handle, buf, buf_size, &readfile_read, NULL)) { keepon = FALSE; result = CURLE_READ_ERROR; break; } - result = send_telnet_data(data, buffer, readfile_read); + result = send_telnet_data(data, buf, readfile_read); if(result) { keepon = FALSE; break; @@ -1469,8 +1465,8 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) } if(events.lNetworkEvents & FD_READ) { /* read data from network */ - result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread); - /* read would have blocked. Loop again */ + result = Curl_read(data, sockfd, buf, data->set.buffer_size, &nread); + /* read would've blocked. Loop again */ if(result == CURLE_AGAIN) break; /* returned not-zero, this an error */ @@ -1485,14 +1481,14 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) break; } - result = telrcv(data, (unsigned char *) buffer, nread); + result = telrcv(data, (unsigned char *) buf, nread); if(result) { keepon = FALSE; break; } /* Negotiate if the peer has started negotiating, - otherwise do not. We do not want to speak telnet with + otherwise don't. We don't want to speak telnet with non-telnet servers, like POP or SMTP. */ if(tn->please_negotiate && !tn->already_negotiated) { negotiate(data); @@ -1535,28 +1531,23 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) pfd[1].events = POLLIN; poll_cnt = 2; interval_ms = 1 * 1000; - if(pfd[1].fd < 0) { - failf(data, "cannot read input"); - result = CURLE_RECV_ERROR; - keepon = FALSE; - } } while(keepon) { DEBUGF(infof(data, "telnet_do, poll %d fds", poll_cnt)); - switch(Curl_poll(pfd, (unsigned int)poll_cnt, interval_ms)) { + switch(Curl_poll(pfd, poll_cnt, interval_ms)) { case -1: /* error, stop reading */ keepon = FALSE; continue; case 0: /* timeout */ pfd[0].revents = 0; pfd[1].revents = 0; - FALLTHROUGH(); + /* FALLTHROUGH */ default: /* read! */ if(pfd[0].revents & POLLIN) { /* read data from network */ - result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread); - /* read would have blocked. Loop again */ + result = Curl_read(data, sockfd, buf, data->set.buffer_size, &nread); + /* read would've blocked. Loop again */ if(result == CURLE_AGAIN) break; /* returned not-zero, this an error */ @@ -1581,14 +1572,14 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) total_dl += nread; result = Curl_pgrsSetDownloadCounter(data, total_dl); if(!result) - result = telrcv(data, (unsigned char *)buffer, nread); + result = telrcv(data, (unsigned char *)buf, nread); if(result) { keepon = FALSE; break; } /* Negotiate if the peer has started negotiating, - otherwise do not. We do not want to speak telnet with + otherwise don't. We don't want to speak telnet with non-telnet servers, like POP or SMTP. */ if(tn->please_negotiate && !tn->already_negotiated) { negotiate(data); @@ -1599,12 +1590,12 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) nread = 0; if(poll_cnt == 2) { if(pfd[1].revents & POLLIN) { /* read from in file */ - nread = read(pfd[1].fd, buffer, sizeof(buffer)); + nread = read(pfd[1].fd, buf, data->set.buffer_size); } } else { /* read from user-supplied method */ - nread = (int)data->state.fread_func(buffer, 1, sizeof(buffer), + nread = (int)data->state.fread_func(buf, 1, data->set.buffer_size, data->state.in); if(nread == CURL_READFUNC_ABORT) { keepon = FALSE; @@ -1615,7 +1606,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) } if(nread > 0) { - result = send_telnet_data(data, buffer, nread); + result = send_telnet_data(data, buf, nread); if(result) { keepon = FALSE; break; @@ -1645,7 +1636,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) } #endif /* mark this as "no further transfer wanted" */ - Curl_xfer_setup_nop(data); + Curl_setup_transfer(data, -1, -1, FALSE, -1); return result; } |