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