1*38905Sborman /* 2*38905Sborman * Copyright (c) 1989 Regents of the University of California. 3*38905Sborman * All rights reserved. 4*38905Sborman * 5*38905Sborman * Redistribution and use in source and binary forms are permitted 6*38905Sborman * provided that the above copyright notice and this paragraph are 7*38905Sborman * duplicated in all such forms and that any documentation, 8*38905Sborman * advertising materials, and other materials related to such 9*38905Sborman * distribution and use acknowledge that the software was developed 10*38905Sborman * by the University of California, Berkeley. The name of the 11*38905Sborman * University may not be used to endorse or promote products derived 12*38905Sborman * from this software without specific prior written permission. 13*38905Sborman * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*38905Sborman * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*38905Sborman * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16*38905Sborman */ 17*38905Sborman 18*38905Sborman #ifndef lint 19*38905Sborman static char sccsid[] = "@(#)utility.c 5.1 (Berkeley) 09/01/89"; 20*38905Sborman #endif /* not lint */ 21*38905Sborman 22*38905Sborman 23*38905Sborman #include "telnetd.h" 24*38905Sborman 25*38905Sborman /* 26*38905Sborman * utility functions performing io related tasks 27*38905Sborman */ 28*38905Sborman 29*38905Sborman /* 30*38905Sborman * ttloop 31*38905Sborman * 32*38905Sborman * A small subroutine to flush the network output buffer, get some data 33*38905Sborman * from the network, and pass it through the telnet state machine. We 34*38905Sborman * also flush the pty input buffer (by dropping its data) if it becomes 35*38905Sborman * too full. 36*38905Sborman */ 37*38905Sborman 38*38905Sborman void 39*38905Sborman ttloop() 40*38905Sborman { 41*38905Sborman void netflush(); 42*38905Sborman 43*38905Sborman if (nfrontp-nbackp) { 44*38905Sborman netflush(); 45*38905Sborman } 46*38905Sborman ncc = read(net, netibuf, sizeof netibuf); 47*38905Sborman if (ncc < 0) { 48*38905Sborman syslog(LOG_INFO, "ttloop: read: %m\n"); 49*38905Sborman exit(1); 50*38905Sborman } else if (ncc == 0) { 51*38905Sborman syslog(LOG_INFO, "ttloop: peer died: %m\n"); 52*38905Sborman exit(1); 53*38905Sborman } 54*38905Sborman netip = netibuf; 55*38905Sborman telrcv(); /* state machine */ 56*38905Sborman if (ncc > 0) { 57*38905Sborman pfrontp = pbackp = ptyobuf; 58*38905Sborman telrcv(); 59*38905Sborman } 60*38905Sborman } /* end of ttloop */ 61*38905Sborman 62*38905Sborman /* 63*38905Sborman * Check a descriptor to see if out of band data exists on it. 64*38905Sborman */ 65*38905Sborman stilloob(s) 66*38905Sborman int s; /* socket number */ 67*38905Sborman { 68*38905Sborman static struct timeval timeout = { 0 }; 69*38905Sborman fd_set excepts; 70*38905Sborman int value; 71*38905Sborman 72*38905Sborman do { 73*38905Sborman FD_ZERO(&excepts); 74*38905Sborman FD_SET(s, &excepts); 75*38905Sborman value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); 76*38905Sborman } while ((value == -1) && (errno == EINTR)); 77*38905Sborman 78*38905Sborman if (value < 0) { 79*38905Sborman fatalperror(pty, "select"); 80*38905Sborman } 81*38905Sborman if (FD_ISSET(s, &excepts)) { 82*38905Sborman return 1; 83*38905Sborman } else { 84*38905Sborman return 0; 85*38905Sborman } 86*38905Sborman } 87*38905Sborman 88*38905Sborman ptyflush() 89*38905Sborman { 90*38905Sborman int n; 91*38905Sborman 92*38905Sborman if ((n = pfrontp - pbackp) > 0) 93*38905Sborman n = write(pty, pbackp, n); 94*38905Sborman if (n < 0) 95*38905Sborman return; 96*38905Sborman pbackp += n; 97*38905Sborman if (pbackp == pfrontp) 98*38905Sborman pbackp = pfrontp = ptyobuf; 99*38905Sborman } 100*38905Sborman 101*38905Sborman /* 102*38905Sborman * nextitem() 103*38905Sborman * 104*38905Sborman * Return the address of the next "item" in the TELNET data 105*38905Sborman * stream. This will be the address of the next character if 106*38905Sborman * the current address is a user data character, or it will 107*38905Sborman * be the address of the character following the TELNET command 108*38905Sborman * if the current address is a TELNET IAC ("I Am a Command") 109*38905Sborman * character. 110*38905Sborman */ 111*38905Sborman char * 112*38905Sborman nextitem(current) 113*38905Sborman char *current; 114*38905Sborman { 115*38905Sborman if ((*current&0xff) != IAC) { 116*38905Sborman return current+1; 117*38905Sborman } 118*38905Sborman switch (*(current+1)&0xff) { 119*38905Sborman case DO: 120*38905Sborman case DONT: 121*38905Sborman case WILL: 122*38905Sborman case WONT: 123*38905Sborman return current+3; 124*38905Sborman case SB: /* loop forever looking for the SE */ 125*38905Sborman { 126*38905Sborman register char *look = current+2; 127*38905Sborman 128*38905Sborman for (;;) { 129*38905Sborman if ((*look++&0xff) == IAC) { 130*38905Sborman if ((*look++&0xff) == SE) { 131*38905Sborman return look; 132*38905Sborman } 133*38905Sborman } 134*38905Sborman } 135*38905Sborman } 136*38905Sborman default: 137*38905Sborman return current+2; 138*38905Sborman } 139*38905Sborman } /* end of nextitem */ 140*38905Sborman 141*38905Sborman 142*38905Sborman /* 143*38905Sborman * netclear() 144*38905Sborman * 145*38905Sborman * We are about to do a TELNET SYNCH operation. Clear 146*38905Sborman * the path to the network. 147*38905Sborman * 148*38905Sborman * Things are a bit tricky since we may have sent the first 149*38905Sborman * byte or so of a previous TELNET command into the network. 150*38905Sborman * So, we have to scan the network buffer from the beginning 151*38905Sborman * until we are up to where we want to be. 152*38905Sborman * 153*38905Sborman * A side effect of what we do, just to keep things 154*38905Sborman * simple, is to clear the urgent data pointer. The principal 155*38905Sborman * caller should be setting the urgent data pointer AFTER calling 156*38905Sborman * us in any case. 157*38905Sborman */ 158*38905Sborman netclear() 159*38905Sborman { 160*38905Sborman register char *thisitem, *next; 161*38905Sborman char *good; 162*38905Sborman #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 163*38905Sborman ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 164*38905Sborman 165*38905Sborman thisitem = netobuf; 166*38905Sborman 167*38905Sborman while ((next = nextitem(thisitem)) <= nbackp) { 168*38905Sborman thisitem = next; 169*38905Sborman } 170*38905Sborman 171*38905Sborman /* Now, thisitem is first before/at boundary. */ 172*38905Sborman 173*38905Sborman good = netobuf; /* where the good bytes go */ 174*38905Sborman 175*38905Sborman while (nfrontp > thisitem) { 176*38905Sborman if (wewant(thisitem)) { 177*38905Sborman int length; 178*38905Sborman 179*38905Sborman next = thisitem; 180*38905Sborman do { 181*38905Sborman next = nextitem(next); 182*38905Sborman } while (wewant(next) && (nfrontp > next)); 183*38905Sborman length = next-thisitem; 184*38905Sborman bcopy(thisitem, good, length); 185*38905Sborman good += length; 186*38905Sborman thisitem = next; 187*38905Sborman } else { 188*38905Sborman thisitem = nextitem(thisitem); 189*38905Sborman } 190*38905Sborman } 191*38905Sborman 192*38905Sborman nbackp = netobuf; 193*38905Sborman nfrontp = good; /* next byte to be sent */ 194*38905Sborman neturg = 0; 195*38905Sborman } /* end of netclear */ 196*38905Sborman 197*38905Sborman /* 198*38905Sborman * netflush 199*38905Sborman * Send as much data as possible to the network, 200*38905Sborman * handling requests for urgent data. 201*38905Sborman */ 202*38905Sborman void 203*38905Sborman netflush() 204*38905Sborman { 205*38905Sborman int n; 206*38905Sborman extern int not42; 207*38905Sborman 208*38905Sborman if ((n = nfrontp - nbackp) > 0) { 209*38905Sborman /* 210*38905Sborman * if no urgent data, or if the other side appears to be an 211*38905Sborman * old 4.2 client (and thus unable to survive TCP urgent data), 212*38905Sborman * write the entire buffer in non-OOB mode. 213*38905Sborman */ 214*38905Sborman if ((neturg == 0) || (not42 == 0)) { 215*38905Sborman n = write(net, nbackp, n); /* normal write */ 216*38905Sborman } else { 217*38905Sborman n = neturg - nbackp; 218*38905Sborman /* 219*38905Sborman * In 4.2 (and 4.3) systems, there is some question about 220*38905Sborman * what byte in a sendOOB operation is the "OOB" data. 221*38905Sborman * To make ourselves compatible, we only send ONE byte 222*38905Sborman * out of band, the one WE THINK should be OOB (though 223*38905Sborman * we really have more the TCP philosophy of urgent data 224*38905Sborman * rather than the Unix philosophy of OOB data). 225*38905Sborman */ 226*38905Sborman if (n > 1) { 227*38905Sborman n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ 228*38905Sborman } else { 229*38905Sborman n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ 230*38905Sborman } 231*38905Sborman } 232*38905Sborman } 233*38905Sborman if (n < 0) { 234*38905Sborman if (errno == EWOULDBLOCK || errno == EINTR) 235*38905Sborman return; 236*38905Sborman cleanup(); 237*38905Sborman } 238*38905Sborman nbackp += n; 239*38905Sborman if (nbackp >= neturg) { 240*38905Sborman neturg = 0; 241*38905Sborman } 242*38905Sborman if (nbackp == nfrontp) { 243*38905Sborman nbackp = nfrontp = netobuf; 244*38905Sborman } 245*38905Sborman return; 246*38905Sborman } /* end of netflush */ 247*38905Sborman 248*38905Sborman 249*38905Sborman /* 250*38905Sborman * writenet 251*38905Sborman * 252*38905Sborman * Just a handy little function to write a bit of raw data to the net. 253*38905Sborman * It will force a transmit of the buffer if necessary 254*38905Sborman * 255*38905Sborman * arguments 256*38905Sborman * ptr - A pointer to a character string to write 257*38905Sborman * len - How many bytes to write 258*38905Sborman */ 259*38905Sborman writenet(ptr, len) 260*38905Sborman register char *ptr; 261*38905Sborman register int len; 262*38905Sborman { 263*38905Sborman /* flush buffer if no room for new data) */ 264*38905Sborman if ((&netobuf[BUFSIZ] - nfrontp) < len) { 265*38905Sborman /* if this fails, don't worry, buffer is a little big */ 266*38905Sborman netflush(); 267*38905Sborman } 268*38905Sborman 269*38905Sborman bcopy(ptr, nfrontp, len); 270*38905Sborman nfrontp += len; 271*38905Sborman 272*38905Sborman } /* end of writenet */ 273*38905Sborman 274*38905Sborman 275*38905Sborman /* 276*38905Sborman * miscellaneous functions doing a variety of little jobs follow ... 277*38905Sborman */ 278*38905Sborman 279*38905Sborman 280*38905Sborman fatal(f, msg) 281*38905Sborman int f; 282*38905Sborman char *msg; 283*38905Sborman { 284*38905Sborman char buf[BUFSIZ]; 285*38905Sborman 286*38905Sborman (void) sprintf(buf, "telnetd: %s.\r\n", msg); 287*38905Sborman (void) write(f, buf, (int)strlen(buf)); 288*38905Sborman sleep(1); /*XXX*/ 289*38905Sborman exit(1); 290*38905Sborman } 291*38905Sborman 292*38905Sborman fatalperror(f, msg) 293*38905Sborman int f; 294*38905Sborman char *msg; 295*38905Sborman { 296*38905Sborman char buf[BUFSIZ]; 297*38905Sborman extern char *sys_errlist[]; 298*38905Sborman 299*38905Sborman (void) sprintf(buf, "%s: %s\r\n", msg, sys_errlist[errno]); 300*38905Sborman fatal(f, buf); 301*38905Sborman } 302*38905Sborman 303*38905Sborman char editedhost[32]; 304*38905Sborman 305*38905Sborman edithost(pat, host) 306*38905Sborman register char *pat; 307*38905Sborman register char *host; 308*38905Sborman { 309*38905Sborman register char *res = editedhost; 310*38905Sborman char *strncpy(); 311*38905Sborman 312*38905Sborman if (!pat) 313*38905Sborman pat = ""; 314*38905Sborman while (*pat) { 315*38905Sborman switch (*pat) { 316*38905Sborman 317*38905Sborman case '#': 318*38905Sborman if (*host) 319*38905Sborman host++; 320*38905Sborman break; 321*38905Sborman 322*38905Sborman case '@': 323*38905Sborman if (*host) 324*38905Sborman *res++ = *host++; 325*38905Sborman break; 326*38905Sborman 327*38905Sborman default: 328*38905Sborman *res++ = *pat; 329*38905Sborman break; 330*38905Sborman } 331*38905Sborman if (res == &editedhost[sizeof editedhost - 1]) { 332*38905Sborman *res = '\0'; 333*38905Sborman return; 334*38905Sborman } 335*38905Sborman pat++; 336*38905Sborman } 337*38905Sborman if (*host) 338*38905Sborman (void) strncpy(res, host, 339*38905Sborman sizeof editedhost - (res - editedhost) -1); 340*38905Sborman else 341*38905Sborman *res = '\0'; 342*38905Sborman editedhost[sizeof editedhost - 1] = '\0'; 343*38905Sborman } 344*38905Sborman 345*38905Sborman static char *putlocation; 346*38905Sborman 347*38905Sborman putstr(s) 348*38905Sborman register char *s; 349*38905Sborman { 350*38905Sborman 351*38905Sborman while (*s) 352*38905Sborman putchr(*s++); 353*38905Sborman } 354*38905Sborman 355*38905Sborman putchr(cc) 356*38905Sborman { 357*38905Sborman *putlocation++ = cc; 358*38905Sborman } 359*38905Sborman 360*38905Sborman putf(cp, where) 361*38905Sborman register char *cp; 362*38905Sborman char *where; 363*38905Sborman { 364*38905Sborman char *slash; 365*38905Sborman #ifndef NO_GETTYTAB 366*38905Sborman char datebuffer[60]; 367*38905Sborman #endif /* NO_GETTYTAB */ 368*38905Sborman extern char *rindex(); 369*38905Sborman 370*38905Sborman putlocation = where; 371*38905Sborman 372*38905Sborman while (*cp) { 373*38905Sborman if (*cp != '%') { 374*38905Sborman putchr(*cp++); 375*38905Sborman continue; 376*38905Sborman } 377*38905Sborman switch (*++cp) { 378*38905Sborman 379*38905Sborman case 't': 380*38905Sborman slash = rindex(line, '/'); 381*38905Sborman if (slash == (char *) 0) 382*38905Sborman putstr(line); 383*38905Sborman else 384*38905Sborman putstr(&slash[1]); 385*38905Sborman break; 386*38905Sborman 387*38905Sborman case 'h': 388*38905Sborman putstr(editedhost); 389*38905Sborman break; 390*38905Sborman 391*38905Sborman #ifndef NO_GETTYTAB 392*38905Sborman case 'd': 393*38905Sborman get_date(datebuffer); 394*38905Sborman putstr(datebuffer); 395*38905Sborman break; 396*38905Sborman #endif /* NO_GETTYTAB */ 397*38905Sborman 398*38905Sborman case '%': 399*38905Sborman putchr('%'); 400*38905Sborman break; 401*38905Sborman } 402*38905Sborman cp++; 403*38905Sborman } 404*38905Sborman } 405*38905Sborman 406*38905Sborman /*ARGSUSED*/ 407*38905Sborman #ifdef NO_GETTYTAB 408*38905Sborman getent(cp, name) 409*38905Sborman char *cp, *name; 410*38905Sborman { 411*38905Sborman return(0); 412*38905Sborman } 413*38905Sborman 414*38905Sborman /*ARGSUSED*/ 415*38905Sborman char * 416*38905Sborman getstr(cp, cpp) 417*38905Sborman char *cp, **cpp; 418*38905Sborman { 419*38905Sborman return(0); 420*38905Sborman } 421*38905Sborman #endif /* NO_GETTYTAB */ 422