checked in for Marc; needed USE_OLD_TTY
[unix-history] / usr / src / libexec / telnetd / utility.c
CommitLineData
ea139302
PB
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
396aa79f 19static char sccsid[] = "@(#)utility.c 5.2 (Berkeley) %G%";
ea139302
PB
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
38void
39ttloop()
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 */
65stilloob(s)
66int 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
88ptyflush()
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 */
111char *
112nextitem(current)
113char *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 */
158netclear()
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 */
202void
203netflush()
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 */
259writenet(ptr, len)
260register char *ptr;
261register 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
280fatal(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
292fatalperror(f, msg)
293 int f;
294 char *msg;
295{
396aa79f 296 char buf[BUFSIZ], *strerror();
ea139302 297
396aa79f 298 (void) sprintf(buf, "%s: %s\r\n", msg, strerror(errno));
ea139302
PB
299 fatal(f, buf);
300}
301
302char editedhost[32];
303
304edithost(pat, host)
305 register char *pat;
306 register char *host;
307{
308 register char *res = editedhost;
309 char *strncpy();
310
311 if (!pat)
312 pat = "";
313 while (*pat) {
314 switch (*pat) {
315
316 case '#':
317 if (*host)
318 host++;
319 break;
320
321 case '@':
322 if (*host)
323 *res++ = *host++;
324 break;
325
326 default:
327 *res++ = *pat;
328 break;
329 }
330 if (res == &editedhost[sizeof editedhost - 1]) {
331 *res = '\0';
332 return;
333 }
334 pat++;
335 }
336 if (*host)
337 (void) strncpy(res, host,
338 sizeof editedhost - (res - editedhost) -1);
339 else
340 *res = '\0';
341 editedhost[sizeof editedhost - 1] = '\0';
342}
343
344static char *putlocation;
345
346putstr(s)
347register char *s;
348{
349
350 while (*s)
351 putchr(*s++);
352}
353
354putchr(cc)
355{
356 *putlocation++ = cc;
357}
358
359putf(cp, where)
360register char *cp;
361char *where;
362{
363 char *slash;
364#ifndef NO_GETTYTAB
365 char datebuffer[60];
366#endif /* NO_GETTYTAB */
367 extern char *rindex();
368
369 putlocation = where;
370
371 while (*cp) {
372 if (*cp != '%') {
373 putchr(*cp++);
374 continue;
375 }
376 switch (*++cp) {
377
378 case 't':
379 slash = rindex(line, '/');
380 if (slash == (char *) 0)
381 putstr(line);
382 else
383 putstr(&slash[1]);
384 break;
385
386 case 'h':
387 putstr(editedhost);
388 break;
389
390#ifndef NO_GETTYTAB
391 case 'd':
392 get_date(datebuffer);
393 putstr(datebuffer);
394 break;
395#endif /* NO_GETTYTAB */
396
397 case '%':
398 putchr('%');
399 break;
400 }
401 cp++;
402 }
403}
404
405/*ARGSUSED*/
406#ifdef NO_GETTYTAB
407getent(cp, name)
408char *cp, *name;
409{
410 return(0);
411}
412
413/*ARGSUSED*/
414char *
415getstr(cp, cpp)
416char *cp, **cpp;
417{
418 return(0);
419}
420#endif /* NO_GETTYTAB */