add hp300 support from Utah
[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
19static char sccsid[] = "@(#)utility.c 5.1 (Berkeley) %G%";
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{
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
303char editedhost[32];
304
305edithost(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
345static char *putlocation;
346
347putstr(s)
348register char *s;
349{
350
351 while (*s)
352 putchr(*s++);
353}
354
355putchr(cc)
356{
357 *putlocation++ = cc;
358}
359
360putf(cp, where)
361register char *cp;
362char *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
408getent(cp, name)
409char *cp, *name;
410{
411 return(0);
412}
413
414/*ARGSUSED*/
415char *
416getstr(cp, cpp)
417char *cp, **cpp;
418{
419 return(0);
420}
421#endif /* NO_GETTYTAB */