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)); wontoption P((int));
int output_data __P((const char *, ...)) __printflike(1, 2); 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 #ifdef ENCRYPTION
extern void (*encrypt_output) P((unsigned char *, int)); extern void (*encrypt_output) P((unsigned char *, int));

View File

@ -176,7 +176,6 @@ end_slc(bufp)
register unsigned char **bufp; register unsigned char **bufp;
{ {
register int len; register int len;
void netflush();
/* /*
* If a change has occured, store the new terminal control * 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. * 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 int
output_data(const char *format, ...) output_data(const char *format, ...)
{ {
va_list args; va_list args;
size_t remaining, ret; int len;
char *buf;
va_start(args, format); va_start(args, format);
remaining = BUFSIZ - (nfrontp - netobuf); if ((len = vasprintf(&buf, format, args)) == -1)
/* try a netflush() if the room is too low */ return -1;
if (strlen(format) > remaining || BUFSIZ / 4 > remaining) { output_datalen(buf, len);
netflush();
remaining = BUFSIZ - (nfrontp - netobuf);
}
ret = vsnprintf(nfrontp, remaining, format, args);
nfrontp += (ret < remaining) ? ret : remaining;
va_end(args); va_end(args);
return ret; free(buf);
}
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;
return (len); 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 *HE;
char *HN; char *HN;
char *IM; char *IM;
void netflush();
int nfd; int nfd;
/* /*

View File

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

View File

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