output_data(), output_datalen() and netflush() didn't actually guarantee

to do what they are supposed to: under some circumstances output data would
be truncated, or the buffer would not actually be flushed (possibly leading
to overflows when the caller assumes the operation succeeded).  Change the
semantics so that these functions ensure they complete the operation before
returning.

Comment out diagnostic code enabled by '-D reports' which causes an
infinite recursion and an eventual crash.

Patch developed with assistance from ru and assar.


git-svn-id: http://svn0.us-east.freebsd.org/base/head/contrib/telnet@80224 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f
This commit is contained in:
kris 2001-07-23 21:52:26 +00:00
parent 2c684cfa07
commit 9de6e7ba10
6 changed files with 54 additions and 49 deletions

View File

@ -190,7 +190,7 @@ extern void
wontoption P((int));
int output_data __P((const char *, ...)) __printflike(1, 2);
int output_datalen __P((const char *, size_t));
void output_datalen __P((const char *, int));
#ifdef ENCRYPTION
extern void (*encrypt_output) P((unsigned char *, int));

View File

@ -176,7 +176,6 @@ end_slc(bufp)
register unsigned char **bufp;
{
register int len;
void netflush();
/*
* If a change has occured, store the new terminal control

View File

@ -1615,40 +1615,46 @@ send_status()
/*
* This function appends data to nfrontp and advances nfrontp.
* Returns the number of characters written altogether (the
* buffer may have been flushed in the process).
*/
int
output_data(const char *format, ...)
{
va_list args;
size_t remaining, ret;
int len;
char *buf;
va_start(args, format);
remaining = BUFSIZ - (nfrontp - netobuf);
/* try a netflush() if the room is too low */
if (strlen(format) > remaining || BUFSIZ / 4 > remaining) {
netflush();
remaining = BUFSIZ - (nfrontp - netobuf);
}
ret = vsnprintf(nfrontp, remaining, format, args);
nfrontp += (ret < remaining) ? ret : remaining;
if ((len = vasprintf(&buf, format, args)) == -1)
return -1;
output_datalen(buf, len);
va_end(args);
return ret;
}
int
output_datalen(const char *buf, size_t len)
{
size_t remaining;
remaining = BUFSIZ - (nfrontp - netobuf);
if (remaining < len) {
netflush();
remaining = BUFSIZ - (nfrontp - netobuf);
if (remaining < len)
return -1;
}
memmove(nfrontp, buf, len);
nfrontp += len;
free(buf);
return (len);
}
void
output_datalen(const char *buf, int len)
{
int remaining, copied;
remaining = BUFSIZ - (nfrontp - netobuf);
while (len > 0) {
/* Free up enough space if the room is too low*/
if ((len > BUFSIZ ? BUFSIZ : len) > remaining) {
netflush();
remaining = BUFSIZ - (nfrontp - netobuf);
}
/* Copy out as much as will fit */
copied = remaining > len ? len : remaining;
memmove(nfrontp, buf, copied);
nfrontp += copied;
len -= copied;
remaining -= copied;
buf += copied;
}
return;
}

View File

@ -952,7 +952,6 @@ telnet(f, p, host)
char *HE;
char *HN;
char *IM;
void netflush();
int nfd;
/*

View File

@ -140,7 +140,6 @@ int newmap = 1; /* nonzero if \n maps to ^M^J */
void
localstat()
{
void netflush();
int need_will_echo = 0;
#if defined(CRAY2) && defined(UNICOS5)
@ -404,7 +403,6 @@ flowstat()
clientstat(code, parm1, parm2)
register int code, parm1, parm2;
{
void netflush();
/*
* Get a copy of terminal characteristics.

View File

@ -69,10 +69,9 @@ static const char rcsid[] =
void
ttloop()
{
void netflush();
DIAG(TD_REPORT, output_data("td: ttloop\r\n"));
if (nfrontp-nbackp) {
if (nfrontp - nbackp > 0) {
netflush();
}
ncc = read(net, netibuf, sizeof netibuf);
@ -257,10 +256,13 @@ netflush()
int n;
extern int not42;
if ((n = nfrontp - nbackp) > 0) {
while ((n = nfrontp - nbackp) > 0) {
#if 0
/* XXX This causes output_data() to recurse and die */
DIAG(TD_REPORT, {
n += output_data("td: netflush %d chars\r\n", n);
});
#endif
#ifdef ENCRYPTION
if (encrypt_output) {
char *s = nclearto ? nclearto : nbackp;
@ -293,25 +295,26 @@ netflush()
n = send(net, nbackp, n, MSG_OOB); /* URGENT data */
}
}
}
if (n < 0) {
if (errno == EWOULDBLOCK || errno == EINTR)
return;
cleanup(0);
}
nbackp += n;
if (n == -1) {
if (errno == EWOULDBLOCK || errno == EINTR)
continue;
cleanup(0);
/* NOTREACHED */
}
nbackp += n;
#ifdef ENCRYPTION
if (nbackp > nclearto)
nclearto = 0;
if (nbackp > nclearto)
nclearto = 0;
#endif /* ENCRYPTION */
if (nbackp >= neturg) {
neturg = 0;
}
if (nbackp == nfrontp) {
nbackp = nfrontp = netobuf;
if (nbackp >= neturg) {
neturg = 0;
}
if (nbackp == nfrontp) {
nbackp = nfrontp = netobuf;
#ifdef ENCRYPTION
nclearto = 0;
nclearto = 0;
#endif /* ENCRYPTION */
}
}
return;
} /* end of netflush */