* authenc.c (net_write): Rewrite in terms of netwrite()
authorTom Yu <tlyu@mit.edu>
Thu, 2 Aug 2001 22:07:00 +0000 (22:07 +0000)
committerTom Yu <tlyu@mit.edu>
Thu, 2 Aug 2001 22:07:00 +0000 (22:07 +0000)
* configure.in: Check for vsnprintf().

* ext.h: New prototypes for netprintf, netprintf_urg,
netprintf_noflush, netwrite, netputs.

* slc.c: Fix to use new NETOBUF-handling functions.

* state.c: Fix to use new NETOBUF-handling functions.

* telnetd.c: Fix to use new NETOBUF-handling functions.

* termstat.c: Fix to use new NETOBUF-handling functions.

* utility.c: General rework to be more paranoid about
bounds-checking of NETOBUF and NFRONTP.  Abstract away
interactions with NETOBUF to eliminate explicit references to
NFRONTP in many places.
(netwrite): New function; copies a buffer to the
NETOBUF "ring buffer", checking bounds and calling netflush() if
needed.
(netputs): New function; calls netwrite() with a nul-terminated
string.
(netprintf, netprintf_ext): New function; wrap sprintf() with
bounds checking for use with NETOBUF.
(netprintf_urg): New function; like netprintf() except sets neturg
to point at last char written.
(netprintf_noflush): New function; like netprintf() except
silently fails if NETOBUF is full.
(ttloop, printoption, printsub, printdata): Fix to use new
NETOBUF-handling functions.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@13669 dc483132-0cff-0310-8789-dd5450dbe970

src/appl/telnet/telnetd/ChangeLog
src/appl/telnet/telnetd/authenc.c
src/appl/telnet/telnetd/configure.in
src/appl/telnet/telnetd/ext.h
src/appl/telnet/telnetd/slc.c
src/appl/telnet/telnetd/state.c
src/appl/telnet/telnetd/telnetd.c
src/appl/telnet/telnetd/termstat.c
src/appl/telnet/telnetd/utility.c

index c86d1a40aeddae4abfe748bf211ee0003845002f..aa85149e0fc327f44483831e822d1589199b036f 100644 (file)
@@ -1,3 +1,38 @@
+2001-08-02  Tom Yu  <tlyu@mit.edu>
+
+       * authenc.c (net_write): Rewrite in terms of netwrite().
+
+       * configure.in: Check for vsnprintf().
+
+       * ext.h: New prototypes for netprintf, netprintf_urg,
+       netprintf_noflush, netwrite, netputs.
+
+       * slc.c: Fix to use new NETOBUF-handling functions.
+
+       * state.c: Fix to use new NETOBUF-handling functions.
+
+       * telnetd.c: Fix to use new NETOBUF-handling functions.
+
+       * termstat.c: Fix to use new NETOBUF-handling functions.
+
+       * utility.c: General rework to be more paranoid about
+       bounds-checking of NETOBUF and NFRONTP.  Abstract away
+       interactions with NETOBUF to eliminate explicit references to
+       NFRONTP in many places.
+       (netwrite): New function; copies a buffer to the
+       NETOBUF "ring buffer", checking bounds and calling netflush() if
+       needed.
+       (netputs): New function; calls netwrite() with a nul-terminated
+       string.
+       (netprintf, netprintf_ext): New function; wrap sprintf() with
+       bounds checking for use with NETOBUF.
+       (netprintf_urg): New function; like netprintf() except sets neturg
+       to point at last char written.
+       (netprintf_noflush): New function; like netprintf() except
+       silently fails if NETOBUF is full.
+       (ttloop, printoption, printsub, printdata): Fix to use new
+       NETOBUF-handling functions.
+
 2001-07-23  Ezra Peisach  <epeisach@mit.edu>
 
        * sys_term.c (startslave): Get rid of extra argument in call to
index 5736698941dde3b0f6789d3032a2e499ef194243..448895400acab38be21af8b782b5461cbac5cd5e 100644 (file)
 #include "telnetd.h"
 #include <libtelnet/misc.h>
 
-       int
+int
 net_write(str, len)
        unsigned char *str;
        int len;
 {
-       if (nfrontp + len < netobuf + BUFSIZ) {
-               memcpy((void *)nfrontp, (void *)str, len);
-               nfrontp += len;
-               return(len);
-       }
-       return(0);
+       if (len < 0)
+               return 0;
+       return netwrite(str, len);
 }
 
-       void
+void
 net_encrypt()
 {
 #ifdef ENCRYPTION
@@ -87,7 +84,3 @@ telnet_gets(prompt, result, length, echo)
        return((char *)0);
 }
 #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
-
-
-
-
index e808694a75e1f303573ffa269b115b77e871ef72..2252c5bcae01add482551847ea58e4b4170ee3a2 100644 (file)
@@ -23,7 +23,7 @@ fi
 fi
 AC_HEADER_TIME
 AC_CHECK_HEADERS(string.h arpa/nameser.h utmp.h sys/time.h sys/tty.h sac.h sys/ptyvar.h sys/filio.h sys/stream.h sys/utsname.h memory.h)
-AC_CHECK_FUNCS(gettosbyname)
+AC_CHECK_FUNCS(gettosbyname vsnprintf)
 dnl Make our operating system-specific security checks and definitions for
 dnl login.
 dnl
index 428f491a94a7d4a79caaf750b1b9cc0665782525..96a4af9474f19ee5a5c3933cfeb023ac54e68ce9 100644 (file)
@@ -183,8 +183,13 @@ extern void
        tty_setsofttab P((int)),
        tty_tspeed P((int)),
        willoption P((int)),
-       wontoption P((int)),
-       writenet P((unsigned char *, int));
+       wontoption P((int));
+
+extern void netprintf P((const char *, ...));
+extern void netprintf_urg P((const char *fmt, ...));
+extern void netprintf_noflush P((const char *fmt, ...));
+extern int netwrite P((const char *, size_t));
+extern void netputs P((const char *));
 
 #ifdef ENCRYPTION
 extern char    *nclearto;
index 1c68b953feeec4d83aec52c4d6eaecb6232e832e..613674b018d801e54bace81c7737a9828296039f 100644 (file)
@@ -198,7 +198,7 @@ end_slc(bufp)
                        (void) sprintf((char *)slcptr, "%c%c", IAC, SE);
                        slcptr += 2;
                        len = slcptr - slcbuf;
-                       writenet(slcbuf, len);
+                       netwrite(slcbuf, len);
                        netflush();  /* force it out immediately */
                        DIAG(TD_OPTIONS, printsub('>', slcbuf+2, len-2););
                }
index a115b7483fedac15846ecfa3615c9f567f4f146a..62ed7443312f35475461f4557ccf51236a3eb3d3 100644 (file)
@@ -89,7 +89,7 @@ static void sb_auth_complete()
   if (!auth_negotiated) {
     static char *error =
       "An environment option was sent before authentication negotiation completed.\r\nThis may create a security hazard. Connection dropped.\r\n";
-    writenet(error, strlen(error));
+    netputs(error);
     netflush();
     exit(1);
   }
@@ -212,9 +212,7 @@ gotiac:                     switch (c) {
                                }
 
                                netclear();     /* clear buffer back */
-                               *nfrontp++ = IAC;
-                               *nfrontp++ = DM;
-                               neturg = nfrontp-1; /* off by one XXX */
+                               netprintf_urg("%c%c", IAC, DM);
                                DIAG(TD_OPTIONS,
                                        printoption("td: send IAC", DM));
                                break;
@@ -384,9 +382,12 @@ gotiac:                    switch (c) {
                pfrontp = opfrontp;
                pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP,
                                        xbuf2, &oc, BUFSIZ);
-               for (cp = xbuf2; oc > 0; --oc)
-                       if ((*nfrontp++ = *cp++) == IAC)
-                               *nfrontp++ = IAC;
+               for (cp = xbuf2; oc > 0; --oc) {
+                       if (*cp == IAC)
+                               netprintf("%c%c", *cp++, IAC);
+                       else
+                               netprintf("%c", *cp++);
+               }
        }
 #endif /* defined(CRAY2) && defined(UNICOS5) */
 }  /* end of telrcv */
@@ -466,8 +467,7 @@ send_do(option, init)
                        set_his_want_state_will(option);
                do_dont_resp[option]++;
        }
-       (void) sprintf(nfrontp, (char *)doopt, option);
-       nfrontp += sizeof (dont) - 2;
+       netprintf((char *)doopt, option);
 
        DIAG(TD_OPTIONS, printoption("td: send do", option));
 }
@@ -686,8 +686,7 @@ send_dont(option, init)
                set_his_want_state_wont(option);
                do_dont_resp[option]++;
        }
-       (void) sprintf(nfrontp, (char *)dont, option);
-       nfrontp += sizeof (doopt) - 2;
+       netprintf((char *)dont, option);
 
        DIAG(TD_OPTIONS, printoption("td: send dont", option));
 }
@@ -836,8 +835,7 @@ send_will(option, init)
                set_my_want_state_will(option);
                will_wont_resp[option]++;
        }
-       (void) sprintf(nfrontp, (char *)will, option);
-       nfrontp += sizeof (doopt) - 2;
+       netprintf((char *)will, option);
 
        DIAG(TD_OPTIONS, printoption("td: send will", option));
 }
@@ -996,8 +994,7 @@ send_wont(option, init)
                set_my_want_state_wont(option);
                will_wont_resp[option]++;
        }
-       (void) sprintf(nfrontp, (char *)wont, option);
-       nfrontp += sizeof (wont) - 2;
+       netprintf((char *)wont, option);
 
        DIAG(TD_OPTIONS, printoption("td: send wont", option));
 }
@@ -1396,10 +1393,8 @@ suboption()
            env_ovar_wrong:
                        env_ovar = OLD_ENV_VALUE;
                        env_ovalue = OLD_ENV_VAR;
-                       DIAG(TD_OPTIONS, {sprintf(nfrontp,
-                               "ENVIRON VALUE and VAR are reversed!\r\n");
-                               nfrontp += strlen(nfrontp);});
-
+                       DIAG(TD_OPTIONS,
+                            netputs("ENVIRON VALUE and VAR are reversed!\r\n"));
                }
            }
            SB_RESTORE();
@@ -1638,7 +1633,7 @@ send_status()
        ADD(IAC);
        ADD(SE);
 
-       writenet(statusbuf, ncp - statusbuf);
+       netwrite(statusbuf, ncp - statusbuf);
        netflush();     /* Send it on its way */
 
        DIAG(TD_OPTIONS,
index b1ee54c008a41e64f9e7bdba5a42102dd863b560..fc8f260f4e3a17c77e5ea9d152e3061c1df3a590 100644 (file)
@@ -693,7 +693,7 @@ static void encrypt_failure()
     char *lerror_message =
        "Encryption was not successfully negotiated.  Goodbye.\r\n\r\n";
 
-    writenet(lerror_message, strlen(lerror_message));
+    netputs(lerror_message);
     netflush();
     exit(1);
 }
@@ -779,51 +779,26 @@ getterminaltype(name)
     if (his_state_is_will(TELOPT_TSPEED)) {
        static unsigned char sb[] =
                        { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
-
-       if(nfrontp - netobuf + sizeof(sb) < sizeof(netobuf)) {
-           memcpy(nfrontp, sb, sizeof(sb));
-           nfrontp += sizeof(sb);
-           *nfrontp = '\0';
-       }
+       netwrite(sb, sizeof(sb));
     }
     if (his_state_is_will(TELOPT_XDISPLOC)) {
        static unsigned char sb[] =
                        { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
-
-       if(nfrontp - netobuf + sizeof(sb) < sizeof(netobuf)) {
-           memcpy(nfrontp, sb, sizeof(sb));
-           nfrontp += sizeof(sb);
-           *nfrontp = '\0';
-       }
+       netwrite(sb, sizeof(sb));
     }
     if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
        static unsigned char sb[] =
                        { IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE };
-
-       if(nfrontp - netobuf + sizeof(sb) < sizeof(netobuf)) {
-           memcpy(nfrontp, sb, sizeof(sb));
-           nfrontp += sizeof(sb);
-           *nfrontp = '\0';
-       }
+       netwrite(sb, sizeof(sb));
     }
     else if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
        static unsigned char sb[] =
                        { IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE };
-
-       if(nfrontp - netobuf + sizeof(sb) < sizeof(netobuf)) {
-           memcpy(nfrontp, sb, sizeof(sb));
-           nfrontp += sizeof(sb);
-           *nfrontp = '\0';
-       }
+       netwrite(sb, sizeof(sb));
     }
-    if (his_state_is_will(TELOPT_TTYPE)) {
+    if (his_state_is_will(TELOPT_TTYPE))
+       netwrite(ttytype_sbbuf, sizeof(ttytype_sbbuf));
 
-       if(nfrontp - netobuf + sizeof(ttytype_sbbuf) < sizeof(netobuf)) {
-           memcpy(nfrontp, ttytype_sbbuf, sizeof(ttytype_sbbuf));
-           nfrontp += sizeof(ttytype_sbbuf);
-           *nfrontp = '\0';
-       }
-    }
     if (his_state_is_will(TELOPT_TSPEED)) {
        while (sequenceIs(tspeedsubopt, baseline))
            ttloop();
@@ -900,11 +875,7 @@ _gettermname()
     if (his_state_is_wont(TELOPT_TTYPE))
        return;
     settimer(baseline);
-    if(nfrontp - netobuf + sizeof(ttytype_sbbuf)) {
-       memcpy(nfrontp, ttytype_sbbuf, sizeof(ttytype_sbbuf));
-       nfrontp += sizeof(ttytype_sbbuf);
-       *nfrontp = '\0';
-    }
+    netwrite(ttytype_sbbuf, sizeof(ttytype_sbbuf));
     while (sequenceIs(ttypesubopt, baseline))
        ttloop();
 }
@@ -1178,9 +1149,7 @@ telnet(f, p, host)
         * mode, which we do not want.
         */
        if (his_want_state_is_will(TELOPT_ECHO)) {
-               DIAG(TD_OPTIONS,
-                       {sprintf(nfrontp, "td: simulating recv\r\n");
-                        nfrontp += strlen(nfrontp);});
+               DIAG(TD_OPTIONS, netputs("td: simulating recv\r\n"));
                willoption(TELOPT_ECHO);
        }
 
@@ -1309,9 +1278,7 @@ telnet(f, p, host)
        localstat();
 #endif /* LINEMODE */
 
-       DIAG(TD_REPORT,
-               {sprintf(nfrontp, "td: Entering processing loop\r\n");
-                nfrontp += strlen(nfrontp);});
+       DIAG(TD_REPORT, netputs("td: Entering processing loop\r\n"));
 
 #ifdef convex
        startslave(host);
@@ -1436,8 +1403,7 @@ telnet(f, p, host)
                        netip = netibuf;
                    }
                    DIAG((TD_REPORT | TD_NETDATA),
-                           {sprintf(nfrontp, "td: netread %d chars\r\n", ncc);
-                            nfrontp += strlen(nfrontp);});
+                        netprintf("td: netread %d chars\r\n", ncc));
                    DIAG(TD_NETDATA, printdata("nd", netip, ncc));
                }
 
@@ -1484,9 +1450,7 @@ telnet(f, p, host)
                                         * royally if we send them urgent
                                         * mode data.
                                         */
-                                       *nfrontp++ = IAC;
-                                       *nfrontp++ = DM;
-                                       neturg = nfrontp-1; /* off by one XXX */
+                                       netprintf_urg("%c%c", IAC, DM);
 #endif
                                }
                                if (his_state_is_will(TELOPT_LFLOW) &&
@@ -1496,13 +1460,11 @@ telnet(f, p, host)
                                            ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0;
                                        if (newflow != flowmode) {
                                                flowmode = newflow;
-                                               (void) sprintf(nfrontp,
-                                                       "%c%c%c%c%c%c",
+                                               netprintf("%c%c%c%c%c%c",
                                                        IAC, SB, TELOPT_LFLOW,
                                                        flowmode ? LFLOW_ON
                                                                 : LFLOW_OFF,
                                                        IAC, SE);
-                                               nfrontp += 6;
                                        }
                                }
                                pcc--;
@@ -1525,19 +1487,19 @@ telnet(f, p, host)
                                break;
                        c = *ptyip++ & 0377, pcc--;
                        if (c == IAC)
-                               *nfrontp++ = c;
+                               netprintf("%c", c);
 #if    defined(CRAY2) && defined(UNICOS5)
                        else if (c == '\n' &&
                                     my_state_is_wont(TELOPT_BINARY) && newmap)
-                               *nfrontp++ = '\r';
+                               netputs("\r");
 #endif /* defined(CRAY2) && defined(UNICOS5) */
-                       *nfrontp++ = c;
+                       netprintf("%c", c);
                        if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
                                if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
-                                       *nfrontp++ = *ptyip++ & 0377;
+                                       netprintf("%c", *ptyip++ & 0377);
                                        pcc--;
                                } else
-                                       *nfrontp++ = '\0';
+                                       netprintf("%c", '\0');
                        }
                }
 #if    defined(CRAY2) && defined(UNICOS5)
@@ -1699,7 +1661,7 @@ sendsusp()
  * When we get an AYT, if ^T is enabled, use that.  Otherwise,
  * just send back "[Yes]".
  */
-       void
+void
 recv_ayt()
 {
 #if    defined(SIGINFO) && defined(TCSIG)
@@ -1708,10 +1670,7 @@ recv_ayt()
                return;
        }
 #endif
-       (void) strncpy(nfrontp, "\r\n[Yes]\r\n",
-                      sizeof(netobuf) - 1 - (nfrontp - netobuf));
-       nfrontp += 9;
-       *nfrontp = '\0';
+       netputs("\r\n[Yes]\r\n");
 }
 
        void
index 824a1a6494c85639f37ed0e413f1cd0db63566e4..531e16783056f99323f3a69a021330e70cc4d0f9 100644 (file)
@@ -283,10 +283,9 @@ localstat()
 # endif        /* KLUDGELINEMODE */
                        send_do(TELOPT_LINEMODE, 1);
                        /* send along edit modes */
-                       (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, SB,
+                       netprintf("%c%c%c%c%c%c%c", IAC, SB,
                                TELOPT_LINEMODE, LM_MODE, useeditmode,
                                IAC, SE);
-                       nfrontp += 7;
                        editmode = useeditmode;
 # ifdef        KLUDGELINEMODE
                }
@@ -312,10 +311,9 @@ localstat()
                        /*
                         * Send along appropriate edit mode mask.
                         */
-                       (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, SB,
+                       (void) netprintf("%c%c%c%c%c%c%c", IAC, SB,
                                TELOPT_LINEMODE, LM_MODE, useeditmode,
                                IAC, SE);
-                       nfrontp += 7;
                        editmode = useeditmode;
                }
                                                        
@@ -359,20 +357,18 @@ flowstat()
        if (his_state_is_will(TELOPT_LFLOW)) {
                if (tty_flowmode() != flowmode) {
                        flowmode = tty_flowmode();
-                       (void) sprintf(nfrontp, "%c%c%c%c%c%c",
+                       netprintf("%c%c%c%c%c%c",
                                        IAC, SB, TELOPT_LFLOW,
                                        flowmode ? LFLOW_ON : LFLOW_OFF,
                                        IAC, SE);
-                       nfrontp += 6;
                }
                if (tty_restartany() != restartany) {
                        restartany = tty_restartany();
-                       (void) sprintf(nfrontp, "%c%c%c%c%c%c",
+                       netprintf("%c%c%c%c%c%c",
                                        IAC, SB, TELOPT_LFLOW,
                                        restartany ? LFLOW_RESTART_ANY
                                                   : LFLOW_RESTART_XON,
                                        IAC, SE);
-                       nfrontp += 6;
                }
        }
 }
@@ -445,10 +441,9 @@ clientstat(code, parm1, parm2)
                                        useeditmode |= MODE_SOFT_TAB;
                                if (tty_islitecho())
                                        useeditmode |= MODE_LIT_ECHO;
-                               (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC,
+                               netprintf("%c%c%c%c%c%c%c", IAC,
                                        SB, TELOPT_LINEMODE, LM_MODE,
-                                                       useeditmode, IAC, SE);
-                               nfrontp += 7;
+                                       useeditmode, IAC, SE);
                                editmode = useeditmode;
                        }
 
@@ -504,11 +499,10 @@ clientstat(code, parm1, parm2)
                        set_termbuf();
 
                        if (!ack) {
-                               (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC,
+                               netprintf("%c%c%c%c%c%c%c", IAC,
                                        SB, TELOPT_LINEMODE, LM_MODE,
                                        useeditmode|MODE_ACK,
                                        IAC, SE);
-                               nfrontp += 7;
                        }
                
                        editmode = useeditmode;
index dabeeb4ae8dcf4a93618eb381966b98030e02798..106dc69e3fdfc25b76bbf155e9aca55c72aac15e 100644 (file)
@@ -33,6 +33,7 @@
 
 /* based on @(#)utility.c      8.1 (Berkeley) 6/4/93 */
 
+#include <stdarg.h>
 #define PRINTOPTIONS
 #include "telnetd.h"
 
@@ -65,8 +66,7 @@ ttloop()
 {
     void netflush();
 
-    DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop\r\n");
-                    nfrontp += strlen(nfrontp);});
+    DIAG(TD_REPORT, netputs("td: ttloop\r\n"));
     if (nfrontp-nbackp) {
        netflush();
     }
@@ -81,8 +81,7 @@ read_again:
        syslog(LOG_INFO, "ttloop:  peer died: %m");
        exit(1);
     }
-    DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop read %d chars\r\n", ncc);
-                    nfrontp += strlen(nfrontp);});
+    DIAG(TD_REPORT, netprintf("td: ttloop read %d chars\r\n", ncc));
     netip = netibuf;
     telrcv();                  /* state machine */
     if (ncc > 0) {
@@ -125,8 +124,7 @@ ptyflush()
 
        if ((n = pfrontp - pbackp) > 0) {
                DIAG((TD_REPORT | TD_PTYDATA),
-                       { sprintf(nfrontp, "td: ptyflush %d chars\r\n", n);
-                         nfrontp += strlen(nfrontp); });
+                    netprintf("td: ptyflush %d chars\r\n", n));
                DIAG(TD_PTYDATA, printdata("pd", pbackp, n));
                n = write(pty, pbackp, n);
        }
@@ -251,18 +249,15 @@ netclear()
  *             Send as much data as possible to the network,
  *     handling requests for urgent data.
  */
-    void
+void
 netflush()
 {
     int n;
     extern int not42;
 
     if ((n = nfrontp - nbackp) > 0) {
-       DIAG(TD_REPORT,
-           { sprintf(nfrontp, "td: netflush %d chars\r\n", n);
-             n += strlen(nfrontp);  /* get count first */
-             nfrontp += strlen(nfrontp);  /* then move pointer */
-           });
+       DIAG(TD_REPORT, {netprintf_noflush("td: netflush %d chars\r\n", n);
+                        n = nfrontp - nbackp;});
 #ifdef ENCRYPTION
        if (encrypt_output) {
                char *s = nclearto ? nclearto : nbackp;
@@ -319,33 +314,131 @@ netflush()
     return;
 }  /* end of netflush */
 
+/*
+ * L8_256(x) = log8(256**x), rounded up, including sign (for decimal
+ * strings too).  log8(256) = 8/3, but we use integer math to round
+ * up.
+ */
+#define L8_256(x) (((x * 8 + 2) / 3) + 1)
 
 /*
- * writenet
+ * netprintf
  *
- * Just a handy little function to write a bit of raw data to the net.
- * It will force a transmit of the buffer if necessary
+ * Do the equivalent of printf() to the NETOBUF "ring buffer",
+ * possibly calling netflush() if needed.
  *
- * arguments
- *    ptr - A pointer to a character string to write
- *    len - How many bytes to write
+ * Thou shalt not call this with a "%s" format; use netputs instead.
+ * We also don't deal with floating point widths in here.
  */
-       void
-writenet(ptr, len)
-       register unsigned char *ptr;
-       register int len;
+void
+netprintf_ext(int noflush, int seturg, const char *fmt, va_list args)
 {
-       /* flush buffer if no room for new data) */
-       if ((&netobuf[BUFSIZ] - nfrontp) < len) {
-               /* if this fails, don't worry, buffer is a little big */
-               netflush();
+       size_t remain;
+       size_t maxoutlen;
+       char buf[BUFSIZ];
+       const char *cp;
+       int len;
+
+       buf[0] = '\0';          /* nul-terminate */
+       remain = sizeof(netobuf) - (nfrontp - netobuf);
+       for (maxoutlen = 0, cp = fmt; *cp; cp++) {
+               if (*cp == '%')
+                       /* Ok so this is slightly overkill... */
+                       maxoutlen += L8_256(sizeof(long));
+               else
+                       maxoutlen++;
        }
+       if (maxoutlen >= sizeof(buf))
+               return;         /* highly unlikely */
 
-       memcpy(nfrontp, ptr, len);
+#ifdef HAVE_VSNPRINTF
+       len = vsnprintf(buf, sizeof(buf), fmt, args);
+#else
+       len = vsprintf(buf, fmt, args); /* XXX need to fix for SunOS? */
+#endif
+
+       /*
+        * The return value from sprintf()-like functions may be the
+        * number of characters that *would* have been output, not the
+        * number actually output.
+        */
+       if (len <= 0 || len > sizeof(buf))
+               return;
+       if (remain < len && !noflush) {
+               netflush();
+               remain = sizeof(netobuf) - (nfrontp - netobuf);
+       }
+       if (remain < len)
+               return;         /* still not enough space? */
+       memcpy(nfrontp, buf, (size_t)len);
        nfrontp += len;
+       if (seturg)
+               neturg = nfrontp - 1;
+}
 
-}  /* end of writenet */
+void
+netprintf(const char *fmt, ...)
+{
+       va_list args;
 
+       va_start(args, fmt);
+       netprintf_ext(0, 0, fmt, args);
+       va_end(args);
+}
+
+void
+netprintf_urg(const char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       netprintf_ext(0, 1, fmt, args);
+       va_end(args);
+}
+
+void
+netprintf_noflush(const char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       netprintf_ext(1, 0, fmt, args);
+       va_end(args);
+}
+
+/*
+ * netwrite
+ *
+ * Copy BUF into the NETOBUF "ring buffer", possibly calling
+ * netflush() if needed.
+ */
+int
+netwrite(const char *buf, size_t len)
+{
+       size_t remain;
+
+       remain = sizeof(netobuf) - (nfrontp - netobuf);
+       if (remain < len) {
+               netflush();
+               remain = sizeof(netobuf) - (nfrontp - netobuf);
+       }
+       if (remain < len)
+               return 0;
+       memcpy(nfrontp, buf, len);
+       nfrontp += len;
+       return len;
+}
+
+/*
+ * netputs
+ *
+ * Write S to the NETOBUF "ring buffer".  Does not write a '\n'.
+ */
+void
+netputs(const char *s)
+{
+       netwrite(s, strlen(s));
+}
 
 /*
  * miscellaneous functions doing a variety of little jobs follow ...
@@ -529,22 +622,26 @@ putf(cp, where)
 /*
  * Print telnet options and commands in plain text, if possible.
  */
-       void
+void
 printoption(fmt, option)
        register char *fmt;
        register int option;
 {
-       if (TELOPT_OK(option))
-               sprintf(nfrontp, "%s %s\r\n", fmt, TELOPT(option));
-       else if (TELCMD_OK(option))
-               sprintf(nfrontp, "%s %s\r\n", fmt, TELCMD(option));
-       else
-               sprintf(nfrontp, "%s %d\r\n", fmt, option);
-       nfrontp += strlen(nfrontp);
+       netputs(fmt);
+       netputs(" ");
+       if (TELOPT_OK(option)) {
+               netputs(TELOPT(option));
+               netputs("\r\n");
+       } else if (TELCMD_OK(option)) {
+               netputs(TELCMD(option));
+               netputs("\r\n");
+       } else {
+               netprintf("%d\r\n", option);
+       }
        return;
 }
 
-    void
+void
 printsub(direction, pointer, length)
     char               direction;      /* '<' or '>' */
     unsigned char      *pointer;       /* where suboption data sits */
@@ -557,9 +654,9 @@ printsub(direction, pointer, length)
                return;
 
        if (direction) {
-           sprintf(nfrontp, "td: %s suboption ",
-                                       direction == '<' ? "recv" : "send");
-           nfrontp += strlen(nfrontp);
+           netputs("td: ");
+           netputs(direction == '<' ? "recv" : "send");
+           netputs(" suboption ");
            if (length >= 3) {
                register int j;
 
@@ -567,261 +664,223 @@ printsub(direction, pointer, length)
                j = pointer[length-1];
 
                if (i != IAC || j != SE) {
-                   sprintf(nfrontp, "(terminated by ");
-                   nfrontp += strlen(nfrontp);
+                   netputs("(terminated by ");
                    if (TELOPT_OK(i))
-                       sprintf(nfrontp, "%s ", TELOPT(i));
+                       netputs(TELOPT(i));
                    else if (TELCMD_OK(i))
-                       sprintf(nfrontp, "%s ", TELCMD(i));
+                       netputs(TELCMD(i));
                    else
-                       sprintf(nfrontp, "%d ", i);
-                   nfrontp += strlen(nfrontp);
+                       netprintf("%d", i);
+                   netputs(" ");
                    if (TELOPT_OK(j))
-                       sprintf(nfrontp, "%s", TELOPT(j));
+                       netputs(TELOPT(j));
                    else if (TELCMD_OK(j))
-                       sprintf(nfrontp, "%s", TELCMD(j));
+                       netputs(TELCMD(j));
                    else
-                       sprintf(nfrontp, "%d", j);
-                   nfrontp += strlen(nfrontp);
-                   sprintf(nfrontp, ", not IAC SE!) ");
-                   nfrontp += strlen(nfrontp);
+                       netprintf("%d", j);
+                   netputs(", not IAC SE!) ");
                }
            }
            length -= 2;
        }
        if (length < 1) {
-           sprintf(nfrontp, "(Empty suboption??\?)");
-           nfrontp += strlen(nfrontp);
+           netputs("(Empty suboption??\?)");
            return;
        }
        switch (pointer[0]) {
        case TELOPT_TTYPE:
-           sprintf(nfrontp, "TERMINAL-TYPE ");
-           nfrontp += strlen(nfrontp);
+           netputs("TERMINAL-TYPE ");
            switch (pointer[1]) {
            case TELQUAL_IS:
-               sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2);
+               netputs("IS \"");
+               netwrite((char *)pointer + 2, (size_t)(length - 2));
+               netputs("\"");
                break;
            case TELQUAL_SEND:
-               sprintf(nfrontp, "SEND");
+               netputs("SEND");
                break;
            default:
-               sprintf(nfrontp,
-                               "- unknown qualifier %d (0x%x).",
-                               pointer[1], pointer[1]);
+               netprintf("- unknown qualifier %d (0x%x).",
+                         pointer[1], pointer[1]);
            }
-           nfrontp += strlen(nfrontp);
            break;
        case TELOPT_TSPEED:
-           sprintf(nfrontp, "TERMINAL-SPEED");
-           nfrontp += strlen(nfrontp);
+           netputs("TERMINAL-SPEED ");
            if (length < 2) {
-               sprintf(nfrontp, " (empty suboption??\?)");
-               nfrontp += strlen(nfrontp);
+               netputs("(empty suboption??\?)");
                break;
            }
            switch (pointer[1]) {
            case TELQUAL_IS:
-               sprintf(nfrontp, " IS %.*s", length-2, (char *)pointer+2);
-               nfrontp += strlen(nfrontp);
+               netputs("IS ");
+               netwrite((char *)pointer + 2, (size_t)(length - 2));
                break;
            default:
                if (pointer[1] == 1)
-                   sprintf(nfrontp, " SEND");
+                   netputs("SEND");
                else
-                   sprintf(nfrontp, " %d (unknown)", pointer[1]);
-               nfrontp += strlen(nfrontp);
-               for (i = 2; i < length; i++) {
-                   sprintf(nfrontp, " ?%d?", pointer[i]);
-                   nfrontp += strlen(nfrontp);
-               }
+                   netprintf("%d (unknown)", pointer[1]);
+               for (i = 2; i < length; i++)
+                   netprintf(" ?%d?", pointer[i]);
                break;
            }
            break;
 
        case TELOPT_LFLOW:
-           sprintf(nfrontp, "TOGGLE-FLOW-CONTROL");
-           nfrontp += strlen(nfrontp);
+           netputs("TOGGLE-FLOW-CONTROL ");
            if (length < 2) {
-               sprintf(nfrontp, " (empty suboption??\?)");
-               nfrontp += strlen(nfrontp);
+               netputs("(empty suboption??\?)");
                break;
            }
            switch (pointer[1]) {
            case LFLOW_OFF:
-               sprintf(nfrontp, " OFF"); break;
+               netputs("OFF"); break;
            case LFLOW_ON:
-               sprintf(nfrontp, " ON"); break;
+               netputs("ON"); break;
            case LFLOW_RESTART_ANY:
-               sprintf(nfrontp, " RESTART-ANY"); break;
+               netputs("RESTART-ANY"); break;
            case LFLOW_RESTART_XON:
-               sprintf(nfrontp, " RESTART-XON"); break;
+               netputs("RESTART-XON"); break;
            default:
-               sprintf(nfrontp, " %d (unknown)", pointer[1]);
-           }
-           nfrontp += strlen(nfrontp);
-           for (i = 2; i < length; i++) {
-               sprintf(nfrontp, " ?%d?", pointer[i]);
-               nfrontp += strlen(nfrontp);
+               netprintf("%d (unknown)", pointer[1]);
            }
+           for (i = 2; i < length; i++)
+               netprintf(" ?%d?", pointer[i]);
            break;
 
        case TELOPT_NAWS:
-           sprintf(nfrontp, "NAWS");
-           nfrontp += strlen(nfrontp);
+           netputs("NAWS");
            if (length < 2) {
-               sprintf(nfrontp, " (empty suboption??\?)");
-               nfrontp += strlen(nfrontp);
+               netputs(" (empty suboption??\?)");
                break;
            }
            if (length == 2) {
-               sprintf(nfrontp, " ?%d?", pointer[1]);
-               nfrontp += strlen(nfrontp);
+               netprintf(" ?%d?", pointer[1]);
                break;
            }
-           sprintf(nfrontp, " %d %d (%d)",
+           netprintf(" %d %d (%d)",
                pointer[1], pointer[2],
                (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
-           nfrontp += strlen(nfrontp);
            if (length == 4) {
-               sprintf(nfrontp, " ?%d?", pointer[3]);
-               nfrontp += strlen(nfrontp);
+               netprintf(" ?%d?", pointer[3]);
                break;
            }
-           sprintf(nfrontp, " %d %d (%d)",
+           netprintf(" %d %d (%d)",
                pointer[3], pointer[4],
                (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
-           nfrontp += strlen(nfrontp);
-           for (i = 5; i < length; i++) {
-               sprintf(nfrontp, " ?%d?", pointer[i]);
-               nfrontp += strlen(nfrontp);
-           }
+           for (i = 5; i < length; i++)
+               netprintf(" ?%d?", pointer[i]);
            break;
 
        case TELOPT_LINEMODE:
-           sprintf(nfrontp, "LINEMODE ");
-           nfrontp += strlen(nfrontp);
+           netputs("LINEMODE ");
            if (length < 2) {
-               sprintf(nfrontp, " (empty suboption??\?)");
-               nfrontp += strlen(nfrontp);
+               netputs("(empty suboption??\?)");
                break;
            }
            switch (pointer[1]) {
            case WILL:
-               sprintf(nfrontp, "WILL ");
+               netputs("WILL ");
                goto common;
            case WONT:
-               sprintf(nfrontp, "WONT ");
+               netputs("WONT ");
                goto common;
            case DO:
-               sprintf(nfrontp, "DO ");
+               netputs("DO ");
                goto common;
            case DONT:
-               sprintf(nfrontp, "DONT ");
+               netputs("DONT ");
            common:
-               nfrontp += strlen(nfrontp);
                if (length < 3) {
-                   sprintf(nfrontp, "(no option??\?)");
-                   nfrontp += strlen(nfrontp);
+                   netputs("(no option??\?)");
                    break;
                }
                switch (pointer[2]) {
                case LM_FORWARDMASK:
-                   sprintf(nfrontp, "Forward Mask");
-                   nfrontp += strlen(nfrontp);
-                   for (i = 3; i < length; i++) {
-                       sprintf(nfrontp, " %x", pointer[i]);
-                       nfrontp += strlen(nfrontp);
-                   }
+                   netputs("Forward Mask");
+                   for (i = 3; i < length; i++)
+                       netprintf(" %x", pointer[i]);
                    break;
                default:
-                   sprintf(nfrontp, "%d (unknown)", pointer[2]);
-                   nfrontp += strlen(nfrontp);
-                   for (i = 3; i < length; i++) {
-                       sprintf(nfrontp, " %d", pointer[i]);
-                       nfrontp += strlen(nfrontp);
-                   }
+                   netprintf("%d (unknown)", pointer[2]);
+                   for (i = 3; i < length; i++)
+                       netprintf(" %d", pointer[i]);
                    break;
                }
                break;
                
            case LM_SLC:
-               sprintf(nfrontp, "SLC");
-               nfrontp += strlen(nfrontp);
+               netputs("SLC");
                for (i = 2; i < length - 2; i += 3) {
-                   if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
-                       sprintf(nfrontp, " %s", SLC_NAME(pointer[i+SLC_FUNC]));
-                   else
-                       sprintf(nfrontp, " %d", pointer[i+SLC_FUNC]);
-                   nfrontp += strlen(nfrontp);
+                   if (SLC_NAME_OK(pointer[i+SLC_FUNC])) {
+                       netputs(" ");
+                       netputs(SLC_NAME(pointer[i+SLC_FUNC]));
+                   } else
+                       netprintf(" %d", pointer[i+SLC_FUNC]);
                    switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
                    case SLC_NOSUPPORT:
-                       sprintf(nfrontp, " NOSUPPORT"); break;
+                       netputs(" NOSUPPORT"); break;
                    case SLC_CANTCHANGE:
-                       sprintf(nfrontp, " CANTCHANGE"); break;
+                       netputs(" CANTCHANGE"); break;
                    case SLC_VARIABLE:
-                       sprintf(nfrontp, " VARIABLE"); break;
+                       netputs(" VARIABLE"); break;
                    case SLC_DEFAULT:
-                       sprintf(nfrontp, " DEFAULT"); break;
+                       netputs(" DEFAULT"); break;
                    }
-                   nfrontp += strlen(nfrontp);
-                   sprintf(nfrontp, "%s%s%s",
-                       pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
-                       pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
-                       pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
-                   nfrontp += strlen(nfrontp);
+                   netputs(pointer[i+SLC_FLAGS]&SLC_ACK
+                           ? "|ACK" : "");
+                   netputs(pointer[i+SLC_FLAGS]&SLC_FLUSHIN
+                           ? "|FLUSHIN" : "");
+                   netputs(pointer[i+SLC_FLAGS]&SLC_FLUSHOUT
+                           ? "|FLUSHOUT" : "");
                    if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
                                                SLC_FLUSHOUT| SLC_LEVELBITS)) {
-                       sprintf(nfrontp, "(0x%x)", pointer[i+SLC_FLAGS]);
-                       nfrontp += strlen(nfrontp);
+                       netprintf("(0x%x)", pointer[i+SLC_FLAGS]);
                    }
-                   sprintf(nfrontp, " %d;", pointer[i+SLC_VALUE]);
-                   nfrontp += strlen(nfrontp);
+                   netprintf(" %d;", pointer[i+SLC_VALUE]);
                    if ((pointer[i+SLC_VALUE] == IAC) &&
                        (pointer[i+SLC_VALUE+1] == IAC))
                                i++;
                }
-               for (; i < length; i++) {
-                   sprintf(nfrontp, " ?%d?", pointer[i]);
-                   nfrontp += strlen(nfrontp);
-               }
+               for (; i < length; i++)
+                   netprintf(" ?%d?", pointer[i]);
                break;
 
            case LM_MODE:
-               sprintf(nfrontp, "MODE ");
-               nfrontp += strlen(nfrontp);
+               netputs("MODE ");
                if (length < 3) {
-                   sprintf(nfrontp, "(no mode??\?)");
-                   nfrontp += strlen(nfrontp);
+                   netputs("(no mode??\?)");
                    break;
                }
                {
-                   char tbuf[32];
-                   sprintf(tbuf, "%s%s%s%s%s",
-                       pointer[2]&MODE_EDIT ? "|EDIT" : "",
-                       pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
-                       pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
-                       pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
-                       pointer[2]&MODE_ACK ? "|ACK" : "");
-                   sprintf(nfrontp, "%s", tbuf[1] ? &tbuf[1] : "0");
-                   nfrontp += strlen(nfrontp);
-               }
-               if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) {
-                   sprintf(nfrontp, " (0x%x)", pointer[2]);
-                   nfrontp += strlen(nfrontp);
-               }
-               for (i = 3; i < length; i++) {
-                   sprintf(nfrontp, " ?0x%x?", pointer[i]);
-                   nfrontp += strlen(nfrontp);
+                   int wrotemode = 0;
+
+#define NETPUTS_MODE(x)                                \
+do {                                           \
+       if (pointer[2] & (MODE_##x)) {          \
+               if (wrotemode) netputs("|");    \
+               netputs(#x);                    \
+               wrotemode++;                    \
+       }                                       \
+} while (0)
+                   NETPUTS_MODE(EDIT);
+                   NETPUTS_MODE(TRAPSIG);
+                   NETPUTS_MODE(SOFT_TAB);
+                   NETPUTS_MODE(LIT_ECHO);
+                   NETPUTS_MODE(ACK);
+#undef NETPUTS_MODE
+                   if (!wrotemode)
+                       netputs("0");
                }
+               if (pointer[2] & ~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK))
+                   netprintf(" (0x%x)", pointer[2]);
+               for (i = 3; i < length; i++)
+                   netprintf(" ?0x%x?", pointer[i]);
                break;
            default:
-               sprintf(nfrontp, "%d (unknown)", pointer[1]);
-               nfrontp += strlen(nfrontp);
-               for (i = 2; i < length; i++) {
-                   sprintf(nfrontp, " %d", pointer[i]);
-                   nfrontp += strlen(nfrontp);
-               }
+               netprintf("%d (unknown)", pointer[1]);
+               for (i = 2; i < length; i++)
+                   netprintf(" %d", pointer[i]);
            }
            break;
 
@@ -829,24 +888,19 @@ printsub(direction, pointer, length)
            register char *cp;
            register int j, k;
 
-           sprintf(nfrontp, "STATUS");
-           nfrontp += strlen(nfrontp);
+           netputs("STATUS");
 
            switch (pointer[1]) {
            default:
                if (pointer[1] == TELQUAL_SEND)
-                   sprintf(nfrontp, " SEND");
+                   netputs(" SEND");
                else
-                   sprintf(nfrontp, " %d (unknown)", pointer[1]);
-               nfrontp += strlen(nfrontp);
-               for (i = 2; i < length; i++) {
-                   sprintf(nfrontp, " ?%d?", pointer[i]);
-                   nfrontp += strlen(nfrontp);
-               }
+                   netprintf(" %d (unknown)", pointer[1]);
+               for (i = 2; i < length; i++)
+                   netprintf(" ?%d?", pointer[i]);
                break;
            case TELQUAL_IS:
-               sprintf(nfrontp, " IS\r\n");
-               nfrontp += strlen(nfrontp);
+               netputs(" IS\r\n");
 
                for (i = 2; i < length; i++) {
                    switch(pointer[i]) {
@@ -856,19 +910,19 @@ printsub(direction, pointer, length)
                    case WONT:  cp = "WONT"; goto common2;
                    common2:
                        i++;
+                       netputs(" ");
+                       netputs(cp);
+                       netputs(" ");
                        if (TELOPT_OK(pointer[i]))
-                           sprintf(nfrontp, " %s %s", cp, TELOPT(pointer[i]));
+                           netputs(TELOPT(pointer[i]));
                        else
-                           sprintf(nfrontp, " %s %d", cp, pointer[i]);
-                       nfrontp += strlen(nfrontp);
+                           netprintf("%d", pointer[i]);
 
-                       sprintf(nfrontp, "\r\n");
-                       nfrontp += strlen(nfrontp);
+                       netputs("\r\n");
                        break;
 
                    case SB:
-                       sprintf(nfrontp, " SB ");
-                       nfrontp += strlen(nfrontp);
+                       netputs(" SB ");
                        i++;
                        j = k = i;
                        while (j < length) {
@@ -884,20 +938,17 @@ printsub(direction, pointer, length)
                        }
                        printsub(0, &pointer[i], k - i);
                        if (i < length) {
-                           sprintf(nfrontp, " SE");
-                           nfrontp += strlen(nfrontp);
+                           netputs(" SE");
                            i = j;
                        } else
                            i = j - 1;
 
-                       sprintf(nfrontp, "\r\n");
-                       nfrontp += strlen(nfrontp);
+                       netputs("\r\n");
 
                        break;
                                
                    default:
-                       sprintf(nfrontp, " %d", pointer[i]);
-                       nfrontp += strlen(nfrontp);
+                       netprintf(" %d", pointer[i]);
                        break;
                    }
                }
@@ -907,86 +958,79 @@ printsub(direction, pointer, length)
          }
 
        case TELOPT_XDISPLOC:
-           sprintf(nfrontp, "X-DISPLAY-LOCATION ");
-           nfrontp += strlen(nfrontp);
+           netputs("X-DISPLAY-LOCATION ");
            switch (pointer[1]) {
            case TELQUAL_IS:
-               sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2);
+               netputs("IS \"");
+               netwrite((char *)pointer + 2, (size_t)(length - 2));
+               netputs("\"");
                break;
            case TELQUAL_SEND:
-               sprintf(nfrontp, "SEND");
+               netputs("SEND");
                break;
            default:
-               sprintf(nfrontp, "- unknown qualifier %d (0x%x).",
-                               pointer[1], pointer[1]);
+               netprintf("- unknown qualifier %d (0x%x).",
+                         pointer[1], pointer[1]);
            }
-           nfrontp += strlen(nfrontp);
            break;
 
        case TELOPT_NEW_ENVIRON:
-           sprintf(nfrontp, "NEW-ENVIRON ");
+           netputs("NEW-ENVIRON ");
            goto env_common1;
        case TELOPT_OLD_ENVIRON:
-           sprintf(nfrontp, "OLD-ENVIRON");
+           netputs("OLD-ENVIRON ");
        env_common1:
-           nfrontp += strlen(nfrontp);
            switch (pointer[1]) {
            case TELQUAL_IS:
-               sprintf(nfrontp, "IS ");
+               netputs("IS ");
                goto env_common;
            case TELQUAL_SEND:
-               sprintf(nfrontp, "SEND ");
+               netputs("SEND ");
                goto env_common;
            case TELQUAL_INFO:
-               sprintf(nfrontp, "INFO ");
+               netputs("INFO ");
            env_common:
-               nfrontp += strlen(nfrontp);
                {
                    register int noquote = 2;
                    for (i = 2; i < length; i++ ) {
                        switch (pointer[i]) {
                        case NEW_ENV_VAR:
-                           sprintf(nfrontp, "\" VAR " + noquote);
-                           nfrontp += strlen(nfrontp);
+                           netputs("\" VAR " + noquote);
                            noquote = 2;
                            break;
 
                        case NEW_ENV_VALUE:
-                           sprintf(nfrontp, "\" VALUE " + noquote);
-                           nfrontp += strlen(nfrontp);
+                           netputs("\" VALUE " + noquote);
                            noquote = 2;
                            break;
 
                        case ENV_ESC:
-                           sprintf(nfrontp, "\" ESC " + noquote);
-                           nfrontp += strlen(nfrontp);
+                           netputs("\" ESC " + noquote);
                            noquote = 2;
                            break;
 
                        case ENV_USERVAR:
-                           sprintf(nfrontp, "\" USERVAR " + noquote);
-                           nfrontp += strlen(nfrontp);
+                           netputs("\" USERVAR " + noquote);
                            noquote = 2;
                            break;
 
                        default:
                            if (isprint(pointer[i]) && pointer[i] != '"') {
                                if (noquote) {
-                                   *nfrontp++ = '"';
+                                   netputs("\"");
                                    noquote = 0;
                                }
-                               *nfrontp++ = pointer[i];
+                               netprintf("%c", pointer[i]);
                            } else {
-                               sprintf(nfrontp, "\" %03o " + noquote,
-                                                       pointer[i]);
-                               nfrontp += strlen(nfrontp);
+                               netprintf("\" %03o " + noquote,
+                                         pointer[i]);
                                noquote = 2;
                            }
                            break;
                        }
                    }
                    if (!noquote)
-                       *nfrontp++ = '"';
+                       netputs("\"");
                    break;
                }
            }
@@ -994,91 +1038,74 @@ printsub(direction, pointer, length)
 
 #if    defined(AUTHENTICATION)
        case TELOPT_AUTHENTICATION:
-           sprintf(nfrontp, "AUTHENTICATION");
-           nfrontp += strlen(nfrontp);
+           netputs("AUTHENTICATION");
        
            if (length < 2) {
-               sprintf(nfrontp, " (empty suboption??\?)");
-               nfrontp += strlen(nfrontp);
+               netputs(" (empty suboption??\?)");
                break;
            }
            switch (pointer[1]) {
            case TELQUAL_REPLY:
            case TELQUAL_IS:
-               sprintf(nfrontp, " %s ", (pointer[1] == TELQUAL_IS) ?
-                                                       "IS" : "REPLY");
-               nfrontp += strlen(nfrontp);
+               netputs((pointer[1] == TELQUAL_IS) ? " IS " : " REPLY ");
                if (AUTHTYPE_NAME_OK(pointer[2]))
-                   sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[2]));
+                   netputs(AUTHTYPE_NAME(pointer[2]));
                else
-                   sprintf(nfrontp, "%d ", pointer[2]);
-               nfrontp += strlen(nfrontp);
+                   netprintf(" %d ", pointer[2]);
                if (length < 3) {
-                   sprintf(nfrontp, "(partial suboption??\?)");
-                   nfrontp += strlen(nfrontp);
+                   netputs("(partial suboption??\?)");
                    break;
                }
-               sprintf(nfrontp, "%s|%s%s",
-                       ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
-                       "CLIENT" : "SERVER",
-                       ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
-                       "MUTUAL" : "ONE-WAY",
-                       ((pointer[3] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON) ?
-                       "|ENCRYPT" : "");
-               nfrontp += strlen(nfrontp);
+               netputs(((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT)
+                       ? "CLIENT|" : "SERVER|");
+               netputs(((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
+                       ? "MUTUAL" : "ONE-WAY");
+               netputs(((pointer[3] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON)
+                       ? "|ENCRYPT" : "");
 
                auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
-               sprintf(nfrontp, "%s", buf);
-               nfrontp += strlen(nfrontp);
+               netputs(buf);
                break;
 
            case TELQUAL_SEND:
                i = 2;
-               sprintf(nfrontp, " SEND ");
-               nfrontp += strlen(nfrontp);
+               netputs(" SEND ");
                while (i < length) {
                    if (AUTHTYPE_NAME_OK(pointer[i]))
-                       sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[i]));
+                       netputs(AUTHTYPE_NAME(pointer[i]));
                    else
-                       sprintf(nfrontp, "%d ", pointer[i]);
-                   nfrontp += strlen(nfrontp);
+                       netprintf("%d", pointer[i]);
+                   netputs(" ");
                    if (++i >= length) {
-                       sprintf(nfrontp, "(partial suboption??\?)");
-                       nfrontp += strlen(nfrontp);
+                       netputs("(partial suboption??\?)");
                        break;
                    }
-                   sprintf(nfrontp, "%s|%s%s ",
-                       ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
-                                                       "CLIENT" : "SERVER",
-                       ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
-                                                       "MUTUAL" : "ONE-WAY",
-                       ((pointer[3] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON) ?
-                       "|ENCRYPT" : "");
-                   nfrontp += strlen(nfrontp);
+                   netputs(((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT)
+                           ? "CLIENT|" : "SERVER|");
+                   netputs(((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
+                           ? "MUTUAL" : "ONE-WAY");
+                   if ((pointer[3] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON)
+                       netputs("|ENCRYPT");
                    ++i;
                }
                break;
 
            case TELQUAL_NAME:
                i = 2;
-               sprintf(nfrontp, " NAME \"");
-               nfrontp += strlen(nfrontp);
+               netputs(" NAME \"");
                while (i < length) {
                    if (isprint(pointer[i]))
-                       *nfrontp++ = pointer[i++];
+                       netprintf("%c", pointer[i++]);
                    else {
-                       sprintf(nfrontp, "\"%03o",pointer[i++]);
-                       nfrontp += strlen(nfrontp);
+                       netprintf("\\%03o", pointer[i++]);
                    }
                }
-               *nfrontp++ = '"';
+               netputs("\"");
                break;
 
            default:
-                   for (i = 2; i < length; i++) {
-                       sprintf(nfrontp, " ?%d?", pointer[i]);
-                       nfrontp += strlen(nfrontp);
-                   }
+                   for (i = 2; i < length; i++)
+                       netprintf(" ?%d?", pointer[i]);
                    break;
            }
            break;
@@ -1086,87 +1113,74 @@ printsub(direction, pointer, length)
 
 #ifdef ENCRYPTION
        case TELOPT_ENCRYPT:
-           sprintf(nfrontp, "ENCRYPT");
-           nfrontp += strlen(nfrontp);
+           netputs("ENCRYPT");
            if (length < 2) {
-               sprintf(nfrontp, " (empty suboption??\?)");
-               nfrontp += strlen(nfrontp);
+               netputs(" (empty suboption??\?)");
                break;
            }
            switch (pointer[1]) {
            case ENCRYPT_START:
-               sprintf(nfrontp, " START");
-               nfrontp += strlen(nfrontp);
+               netputs(" START");
                break;
 
            case ENCRYPT_END:
-               sprintf(nfrontp, " END");
-               nfrontp += strlen(nfrontp);
+               netputs(" END");
                break;
 
            case ENCRYPT_REQSTART:
-               sprintf(nfrontp, " REQUEST-START");
-               nfrontp += strlen(nfrontp);
+               netputs(" REQUEST-START");
                break;
 
            case ENCRYPT_REQEND:
-               sprintf(nfrontp, " REQUEST-END");
-               nfrontp += strlen(nfrontp);
+               netputs(" REQUEST-END");
                break;
 
            case ENCRYPT_IS:
            case ENCRYPT_REPLY:
-               sprintf(nfrontp, " %s ", (pointer[1] == ENCRYPT_IS) ?
-                                                       "IS" : "REPLY");
-               nfrontp += strlen(nfrontp);
+               netputs((pointer[1] == ENCRYPT_IS)
+                       ? " IS " : " REPLY ");
                if (length < 3) {
-                   sprintf(nfrontp, " (partial suboption??\?)");
+                   netputs(" (partial suboption??\?)");
                    nfrontp += strlen(nfrontp);
                    break;
                }
                if (ENCTYPE_NAME_OK(pointer[2]))
-                   sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[2]));
+                   netputs(ENCTYPE_NAME(pointer[2]));
                else
-                   sprintf(nfrontp, " %d (unknown)", pointer[2]);
-               nfrontp += strlen(nfrontp);
+                   netprintf("%d (unknown)", pointer[2]);
+               netputs(" ");
 
                encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
-               sprintf(nfrontp, "%s", buf);
-               nfrontp += strlen(nfrontp);
+               netputs(buf);
                break;
 
            case ENCRYPT_SUPPORT:
                i = 2;
-               sprintf(nfrontp, " SUPPORT ");
+               netputs(" SUPPORT ");
                nfrontp += strlen(nfrontp);
                while (i < length) {
                    if (ENCTYPE_NAME_OK(pointer[i]))
-                       sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[i]));
+                       netputs(ENCTYPE_NAME(pointer[i]));
                    else
-                       sprintf(nfrontp, "%d ", pointer[i]);
-                   nfrontp += strlen(nfrontp);
+                       netprintf("%d", pointer[i]);
+                   netputs(" ");
                    i++;
                }
                break;
 
            case ENCRYPT_ENC_KEYID:
-               sprintf(nfrontp, " ENC_KEYID");
-               nfrontp += strlen(nfrontp);
+               netputs(" ENC_KEYID");
                goto encommon;
 
            case ENCRYPT_DEC_KEYID:
-               sprintf(nfrontp, " DEC_KEYID");
-               nfrontp += strlen(nfrontp);
+               netputs(" DEC_KEYID");
                goto encommon;
 
            default:
-               sprintf(nfrontp, " %d (unknown)", pointer[1]);
-               nfrontp += strlen(nfrontp);
+               netprintf(" %d (unknown)", pointer[1]);
            encommon:
-               for (i = 2; i < length; i++) {
-                   sprintf(nfrontp, " %d", pointer[i]);
-                   nfrontp += strlen(nfrontp);
-               }
+               for (i = 2; i < length; i++)
+                   netprintf(" %d", pointer[i]);
                break;
            }
            break;
@@ -1174,18 +1188,15 @@ printsub(direction, pointer, length)
 
        default:
            if (TELOPT_OK(pointer[0]))
-               sprintf(nfrontp, "%s (unknown)", TELOPT(pointer[0]));
+               netputs(TELOPT(pointer[0]));
            else
-               sprintf(nfrontp, "%d (unknown)", pointer[i]);
-           nfrontp += strlen(nfrontp);
-           for (i = 1; i < length; i++) {
-               sprintf(nfrontp, " %d", pointer[i]);
-               nfrontp += strlen(nfrontp);
-           }
+               netprintf("%d", pointer[0]);
+           netputs(" (unknown)");
+           for (i = 1; i < length; i++)
+               netprintf(" %d", pointer[i]);
            break;
        }
-       sprintf(nfrontp, "\r\n");
-       nfrontp += strlen(nfrontp);
+       netputs("\r\n");
 }
 
 /*
@@ -1201,32 +1212,26 @@ printdata(tag, ptr, cnt)
        char xbuf[30];
 
        while (cnt) {
-               /* flush net output buffer if no room for new data) */
-               if ((&netobuf[BUFSIZ] - nfrontp) < 80) {
-                       netflush();
-               }
-
                /* add a line of output */
-               sprintf(nfrontp, "%s: ", tag);
-               nfrontp += strlen(nfrontp);
+               netputs(tag);
+               netputs(": ");
                for (i = 0; i < 20 && cnt; i++) {
-                       sprintf(nfrontp, "%02x", *ptr);
+                       netprintf(nfrontp, "%02x", *ptr);
                        nfrontp += strlen(nfrontp); 
                        if (isprint((int) *ptr)) {
                                xbuf[i] = *ptr;
                        } else {
                                xbuf[i] = '.';
                        }
-                       if (i % 2) { 
-                               *nfrontp = ' ';
-                               nfrontp++;
-                       }
+                       if (i % 2)
+                               netputs(" ");
                        cnt--;
                        ptr++;
                }
                xbuf[i] = '\0';
-               sprintf(nfrontp, " %s\r\n", xbuf );
-               nfrontp += strlen(nfrontp);
+               netputs(" ");
+               netputs(xbuf);
+               netputs("\r\n");
        } 
 }
 #endif /* DIAGNOSTICS */