Deleted Added
full compact
utility.c (80224) utility.c (81965)
1/*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35#if 0
36static const char sccsid[] = "@(#)utility.c 8.4 (Berkeley) 5/30/95";
37#endif
38static const char rcsid[] =
1/*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35#if 0
36static const char sccsid[] = "@(#)utility.c 8.4 (Berkeley) 5/30/95";
37#endif
38static const char rcsid[] =
39 "$FreeBSD: head/contrib/telnet/telnetd/utility.c 80224 2001-07-23 21:52:26Z kris $";
39 "$FreeBSD: head/contrib/telnet/telnetd/utility.c 81965 2001-08-20 12:28:40Z markm $";
40#endif /* not lint */
41
42#ifdef __FreeBSD__
43#include <locale.h>
44#include <sys/utsname.h>
45#endif
40#endif /* not lint */
41
42#ifdef __FreeBSD__
43#include <locale.h>
44#include <sys/utsname.h>
45#endif
46#include <string.h>
46#define PRINTOPTIONS
47#include "telnetd.h"
48
49#if defined(AUTHENTICATION)
50#include <libtelnet/auth.h>
51#endif
52#if defined(ENCRYPTION)
53#include <libtelnet/encrypt.h>
54#endif
55
56/*
57 * utility functions performing io related tasks
58 */
59
60/*
61 * ttloop
62 *
63 * A small subroutine to flush the network output buffer, get some data
64 * from the network, and pass it through the telnet state machine. We
65 * also flush the pty input buffer (by dropping its data) if it becomes
66 * too full.
67 */
68
69 void
70ttloop()
71{
72
73 DIAG(TD_REPORT, output_data("td: ttloop\r\n"));
74 if (nfrontp - nbackp > 0) {
75 netflush();
76 }
77 ncc = read(net, netibuf, sizeof netibuf);
78 if (ncc < 0) {
79 syslog(LOG_INFO, "ttloop: read: %m");
80 exit(1);
81 } else if (ncc == 0) {
82 syslog(LOG_INFO, "ttloop: peer died: %m");
83 exit(1);
84 }
85 DIAG(TD_REPORT, output_data("td: ttloop read %d chars\r\n", ncc));
86 netip = netibuf;
87 telrcv(); /* state machine */
88 if (ncc > 0) {
89 pfrontp = pbackp = ptyobuf;
90 telrcv();
91 }
92} /* end of ttloop */
93
94/*
95 * Check a descriptor to see if out of band data exists on it.
96 */
97 int
98stilloob(s)
99 int s; /* socket number */
100{
101 static struct timeval timeout = { 0 };
102 fd_set excepts;
103 int value;
104
105 do {
106 FD_ZERO(&excepts);
107 FD_SET(s, &excepts);
108 memset((char *)&timeout, 0, sizeof timeout);
109 value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
110 } while ((value == -1) && (errno == EINTR));
111
112 if (value < 0) {
113 fatalperror(pty, "select");
114 }
115 if (FD_ISSET(s, &excepts)) {
116 return 1;
117 } else {
118 return 0;
119 }
120}
121
122 void
123ptyflush()
124{
125 int n;
126
127 if ((n = pfrontp - pbackp) > 0) {
128 DIAG(TD_REPORT | TD_PTYDATA,
129 output_data("td: ptyflush %d chars\r\n", n));
130 DIAG(TD_PTYDATA, printdata("pd", pbackp, n));
131 n = write(pty, pbackp, n);
132 }
133 if (n < 0) {
134 if (errno == EWOULDBLOCK || errno == EINTR)
135 return;
136 cleanup(0);
137 }
138 pbackp += n;
139 if (pbackp == pfrontp)
140 pbackp = pfrontp = ptyobuf;
141}
142
143/*
144 * nextitem()
145 *
146 * Return the address of the next "item" in the TELNET data
147 * stream. This will be the address of the next character if
148 * the current address is a user data character, or it will
149 * be the address of the character following the TELNET command
150 * if the current address is a TELNET IAC ("I Am a Command")
151 * character.
152 */
153 char *
154nextitem(current)
155 char *current;
156{
157 if ((*current&0xff) != IAC) {
158 return current+1;
159 }
160 switch (*(current+1)&0xff) {
161 case DO:
162 case DONT:
163 case WILL:
164 case WONT:
165 return current+3;
166 case SB: /* loop forever looking for the SE */
167 {
168 register char *look = current+2;
169
170 for (;;) {
171 if ((*look++&0xff) == IAC) {
172 if ((*look++&0xff) == SE) {
173 return look;
174 }
175 }
176 }
177 }
178 default:
179 return current+2;
180 }
181} /* end of nextitem */
182
183
184/*
185 * netclear()
186 *
187 * We are about to do a TELNET SYNCH operation. Clear
188 * the path to the network.
189 *
190 * Things are a bit tricky since we may have sent the first
191 * byte or so of a previous TELNET command into the network.
192 * So, we have to scan the network buffer from the beginning
193 * until we are up to where we want to be.
194 *
195 * A side effect of what we do, just to keep things
196 * simple, is to clear the urgent data pointer. The principal
197 * caller should be setting the urgent data pointer AFTER calling
198 * us in any case.
199 */
200 void
201netclear()
202{
203 register char *thisitem, *next;
204 char *good;
205#define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
206 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
207
208#ifdef ENCRYPTION
209 thisitem = nclearto > netobuf ? nclearto : netobuf;
210#else /* ENCRYPTION */
211 thisitem = netobuf;
212#endif /* ENCRYPTION */
213
214 while ((next = nextitem(thisitem)) <= nbackp) {
215 thisitem = next;
216 }
217
218 /* Now, thisitem is first before/at boundary. */
219
220#ifdef ENCRYPTION
221 good = nclearto > netobuf ? nclearto : netobuf;
222#else /* ENCRYPTION */
223 good = netobuf; /* where the good bytes go */
224#endif /* ENCRYPTION */
225
226 while (nfrontp > thisitem) {
227 if (wewant(thisitem)) {
228 int length;
229
230 next = thisitem;
231 do {
232 next = nextitem(next);
233 } while (wewant(next) && (nfrontp > next));
234 length = next-thisitem;
235 memmove(good, thisitem, length);
236 good += length;
237 thisitem = next;
238 } else {
239 thisitem = nextitem(thisitem);
240 }
241 }
242
243 nbackp = netobuf;
244 nfrontp = good; /* next byte to be sent */
245 neturg = 0;
246} /* end of netclear */
247
248/*
249 * netflush
250 * Send as much data as possible to the network,
251 * handling requests for urgent data.
252 */
253 void
254netflush()
255{
256 int n;
257 extern int not42;
258
259 while ((n = nfrontp - nbackp) > 0) {
260#if 0
261 /* XXX This causes output_data() to recurse and die */
262 DIAG(TD_REPORT, {
263 n += output_data("td: netflush %d chars\r\n", n);
264 });
265#endif
266#ifdef ENCRYPTION
267 if (encrypt_output) {
268 char *s = nclearto ? nclearto : nbackp;
269 if (nfrontp - s > 0) {
270 (*encrypt_output)((unsigned char *)s, nfrontp-s);
271 nclearto = nfrontp;
272 }
273 }
274#endif /* ENCRYPTION */
275 /*
276 * if no urgent data, or if the other side appears to be an
277 * old 4.2 client (and thus unable to survive TCP urgent data),
278 * write the entire buffer in non-OOB mode.
279 */
280 if ((neturg == 0) || (not42 == 0)) {
281 n = write(net, nbackp, n); /* normal write */
282 } else {
283 n = neturg - nbackp;
284 /*
285 * In 4.2 (and 4.3) systems, there is some question about
286 * what byte in a sendOOB operation is the "OOB" data.
287 * To make ourselves compatible, we only send ONE byte
288 * out of band, the one WE THINK should be OOB (though
289 * we really have more the TCP philosophy of urgent data
290 * rather than the Unix philosophy of OOB data).
291 */
292 if (n > 1) {
293 n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */
294 } else {
295 n = send(net, nbackp, n, MSG_OOB); /* URGENT data */
296 }
297 }
298 if (n == -1) {
299 if (errno == EWOULDBLOCK || errno == EINTR)
300 continue;
301 cleanup(0);
302 /* NOTREACHED */
303 }
304 nbackp += n;
305#ifdef ENCRYPTION
306 if (nbackp > nclearto)
307 nclearto = 0;
308#endif /* ENCRYPTION */
309 if (nbackp >= neturg) {
310 neturg = 0;
311 }
312 if (nbackp == nfrontp) {
313 nbackp = nfrontp = netobuf;
314#ifdef ENCRYPTION
315 nclearto = 0;
316#endif /* ENCRYPTION */
317 }
318 }
319 return;
320} /* end of netflush */
321
322
323/*
324 * miscellaneous functions doing a variety of little jobs follow ...
325 */
326
327
328 void
329fatal(f, msg)
330 int f;
331 char *msg;
332{
333 char buf[BUFSIZ];
334
335 (void) snprintf(buf, sizeof(buf), "telnetd: %s.\r\n", msg);
336#ifdef ENCRYPTION
337 if (encrypt_output) {
338 /*
339 * Better turn off encryption first....
340 * Hope it flushes...
341 */
342 encrypt_send_end();
343 netflush();
344 }
345#endif /* ENCRYPTION */
346 (void) write(f, buf, (int)strlen(buf));
347 sleep(1); /*XXX*/
348 exit(1);
349}
350
351 void
352fatalperror(f, msg)
353 int f;
354 char *msg;
355{
356 char buf[BUFSIZ], *strerror();
357
358 (void) snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(errno));
359 fatal(f, buf);
360}
361
362char editedhost[32];
363
364 void
365edithost(pat, host)
366 register char *pat;
367 register char *host;
368{
369 register char *res = editedhost;
370
371 if (!pat)
372 pat = "";
373 while (*pat) {
374 switch (*pat) {
375
376 case '#':
377 if (*host)
378 host++;
379 break;
380
381 case '@':
382 if (*host)
383 *res++ = *host++;
384 break;
385
386 default:
387 *res++ = *pat;
388 break;
389 }
390 if (res == &editedhost[sizeof editedhost - 1]) {
391 *res = '\0';
392 return;
393 }
394 pat++;
395 }
396 if (*host)
397 (void) strncpy(res, host,
398 sizeof editedhost - (res - editedhost) -1);
399 else
400 *res = '\0';
401 editedhost[sizeof editedhost - 1] = '\0';
402}
403
404static char *putlocation;
405
406 void
407putstr(s)
408 register char *s;
409{
410
411 while (*s)
412 putchr(*s++);
413}
414
415 void
416putchr(cc)
417 int cc;
418{
419 *putlocation++ = cc;
420}
421
422#ifdef __FreeBSD__
423static char fmtstr[] = { "%+" };
424#else
425/*
426 * This is split on two lines so that SCCS will not see the M
427 * between two % signs and expand it...
428 */
429static char fmtstr[] = { "%l:%M\
430%P on %A, %d %B %Y" };
431#endif
432
433 void
434putf(cp, where)
435 register char *cp;
436 char *where;
437{
438 char *slash;
439 time_t t;
440 char db[100];
47#define PRINTOPTIONS
48#include "telnetd.h"
49
50#if defined(AUTHENTICATION)
51#include <libtelnet/auth.h>
52#endif
53#if defined(ENCRYPTION)
54#include <libtelnet/encrypt.h>
55#endif
56
57/*
58 * utility functions performing io related tasks
59 */
60
61/*
62 * ttloop
63 *
64 * A small subroutine to flush the network output buffer, get some data
65 * from the network, and pass it through the telnet state machine. We
66 * also flush the pty input buffer (by dropping its data) if it becomes
67 * too full.
68 */
69
70 void
71ttloop()
72{
73
74 DIAG(TD_REPORT, output_data("td: ttloop\r\n"));
75 if (nfrontp - nbackp > 0) {
76 netflush();
77 }
78 ncc = read(net, netibuf, sizeof netibuf);
79 if (ncc < 0) {
80 syslog(LOG_INFO, "ttloop: read: %m");
81 exit(1);
82 } else if (ncc == 0) {
83 syslog(LOG_INFO, "ttloop: peer died: %m");
84 exit(1);
85 }
86 DIAG(TD_REPORT, output_data("td: ttloop read %d chars\r\n", ncc));
87 netip = netibuf;
88 telrcv(); /* state machine */
89 if (ncc > 0) {
90 pfrontp = pbackp = ptyobuf;
91 telrcv();
92 }
93} /* end of ttloop */
94
95/*
96 * Check a descriptor to see if out of band data exists on it.
97 */
98 int
99stilloob(s)
100 int s; /* socket number */
101{
102 static struct timeval timeout = { 0 };
103 fd_set excepts;
104 int value;
105
106 do {
107 FD_ZERO(&excepts);
108 FD_SET(s, &excepts);
109 memset((char *)&timeout, 0, sizeof timeout);
110 value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
111 } while ((value == -1) && (errno == EINTR));
112
113 if (value < 0) {
114 fatalperror(pty, "select");
115 }
116 if (FD_ISSET(s, &excepts)) {
117 return 1;
118 } else {
119 return 0;
120 }
121}
122
123 void
124ptyflush()
125{
126 int n;
127
128 if ((n = pfrontp - pbackp) > 0) {
129 DIAG(TD_REPORT | TD_PTYDATA,
130 output_data("td: ptyflush %d chars\r\n", n));
131 DIAG(TD_PTYDATA, printdata("pd", pbackp, n));
132 n = write(pty, pbackp, n);
133 }
134 if (n < 0) {
135 if (errno == EWOULDBLOCK || errno == EINTR)
136 return;
137 cleanup(0);
138 }
139 pbackp += n;
140 if (pbackp == pfrontp)
141 pbackp = pfrontp = ptyobuf;
142}
143
144/*
145 * nextitem()
146 *
147 * Return the address of the next "item" in the TELNET data
148 * stream. This will be the address of the next character if
149 * the current address is a user data character, or it will
150 * be the address of the character following the TELNET command
151 * if the current address is a TELNET IAC ("I Am a Command")
152 * character.
153 */
154 char *
155nextitem(current)
156 char *current;
157{
158 if ((*current&0xff) != IAC) {
159 return current+1;
160 }
161 switch (*(current+1)&0xff) {
162 case DO:
163 case DONT:
164 case WILL:
165 case WONT:
166 return current+3;
167 case SB: /* loop forever looking for the SE */
168 {
169 register char *look = current+2;
170
171 for (;;) {
172 if ((*look++&0xff) == IAC) {
173 if ((*look++&0xff) == SE) {
174 return look;
175 }
176 }
177 }
178 }
179 default:
180 return current+2;
181 }
182} /* end of nextitem */
183
184
185/*
186 * netclear()
187 *
188 * We are about to do a TELNET SYNCH operation. Clear
189 * the path to the network.
190 *
191 * Things are a bit tricky since we may have sent the first
192 * byte or so of a previous TELNET command into the network.
193 * So, we have to scan the network buffer from the beginning
194 * until we are up to where we want to be.
195 *
196 * A side effect of what we do, just to keep things
197 * simple, is to clear the urgent data pointer. The principal
198 * caller should be setting the urgent data pointer AFTER calling
199 * us in any case.
200 */
201 void
202netclear()
203{
204 register char *thisitem, *next;
205 char *good;
206#define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
207 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
208
209#ifdef ENCRYPTION
210 thisitem = nclearto > netobuf ? nclearto : netobuf;
211#else /* ENCRYPTION */
212 thisitem = netobuf;
213#endif /* ENCRYPTION */
214
215 while ((next = nextitem(thisitem)) <= nbackp) {
216 thisitem = next;
217 }
218
219 /* Now, thisitem is first before/at boundary. */
220
221#ifdef ENCRYPTION
222 good = nclearto > netobuf ? nclearto : netobuf;
223#else /* ENCRYPTION */
224 good = netobuf; /* where the good bytes go */
225#endif /* ENCRYPTION */
226
227 while (nfrontp > thisitem) {
228 if (wewant(thisitem)) {
229 int length;
230
231 next = thisitem;
232 do {
233 next = nextitem(next);
234 } while (wewant(next) && (nfrontp > next));
235 length = next-thisitem;
236 memmove(good, thisitem, length);
237 good += length;
238 thisitem = next;
239 } else {
240 thisitem = nextitem(thisitem);
241 }
242 }
243
244 nbackp = netobuf;
245 nfrontp = good; /* next byte to be sent */
246 neturg = 0;
247} /* end of netclear */
248
249/*
250 * netflush
251 * Send as much data as possible to the network,
252 * handling requests for urgent data.
253 */
254 void
255netflush()
256{
257 int n;
258 extern int not42;
259
260 while ((n = nfrontp - nbackp) > 0) {
261#if 0
262 /* XXX This causes output_data() to recurse and die */
263 DIAG(TD_REPORT, {
264 n += output_data("td: netflush %d chars\r\n", n);
265 });
266#endif
267#ifdef ENCRYPTION
268 if (encrypt_output) {
269 char *s = nclearto ? nclearto : nbackp;
270 if (nfrontp - s > 0) {
271 (*encrypt_output)((unsigned char *)s, nfrontp-s);
272 nclearto = nfrontp;
273 }
274 }
275#endif /* ENCRYPTION */
276 /*
277 * if no urgent data, or if the other side appears to be an
278 * old 4.2 client (and thus unable to survive TCP urgent data),
279 * write the entire buffer in non-OOB mode.
280 */
281 if ((neturg == 0) || (not42 == 0)) {
282 n = write(net, nbackp, n); /* normal write */
283 } else {
284 n = neturg - nbackp;
285 /*
286 * In 4.2 (and 4.3) systems, there is some question about
287 * what byte in a sendOOB operation is the "OOB" data.
288 * To make ourselves compatible, we only send ONE byte
289 * out of band, the one WE THINK should be OOB (though
290 * we really have more the TCP philosophy of urgent data
291 * rather than the Unix philosophy of OOB data).
292 */
293 if (n > 1) {
294 n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */
295 } else {
296 n = send(net, nbackp, n, MSG_OOB); /* URGENT data */
297 }
298 }
299 if (n == -1) {
300 if (errno == EWOULDBLOCK || errno == EINTR)
301 continue;
302 cleanup(0);
303 /* NOTREACHED */
304 }
305 nbackp += n;
306#ifdef ENCRYPTION
307 if (nbackp > nclearto)
308 nclearto = 0;
309#endif /* ENCRYPTION */
310 if (nbackp >= neturg) {
311 neturg = 0;
312 }
313 if (nbackp == nfrontp) {
314 nbackp = nfrontp = netobuf;
315#ifdef ENCRYPTION
316 nclearto = 0;
317#endif /* ENCRYPTION */
318 }
319 }
320 return;
321} /* end of netflush */
322
323
324/*
325 * miscellaneous functions doing a variety of little jobs follow ...
326 */
327
328
329 void
330fatal(f, msg)
331 int f;
332 char *msg;
333{
334 char buf[BUFSIZ];
335
336 (void) snprintf(buf, sizeof(buf), "telnetd: %s.\r\n", msg);
337#ifdef ENCRYPTION
338 if (encrypt_output) {
339 /*
340 * Better turn off encryption first....
341 * Hope it flushes...
342 */
343 encrypt_send_end();
344 netflush();
345 }
346#endif /* ENCRYPTION */
347 (void) write(f, buf, (int)strlen(buf));
348 sleep(1); /*XXX*/
349 exit(1);
350}
351
352 void
353fatalperror(f, msg)
354 int f;
355 char *msg;
356{
357 char buf[BUFSIZ], *strerror();
358
359 (void) snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(errno));
360 fatal(f, buf);
361}
362
363char editedhost[32];
364
365 void
366edithost(pat, host)
367 register char *pat;
368 register char *host;
369{
370 register char *res = editedhost;
371
372 if (!pat)
373 pat = "";
374 while (*pat) {
375 switch (*pat) {
376
377 case '#':
378 if (*host)
379 host++;
380 break;
381
382 case '@':
383 if (*host)
384 *res++ = *host++;
385 break;
386
387 default:
388 *res++ = *pat;
389 break;
390 }
391 if (res == &editedhost[sizeof editedhost - 1]) {
392 *res = '\0';
393 return;
394 }
395 pat++;
396 }
397 if (*host)
398 (void) strncpy(res, host,
399 sizeof editedhost - (res - editedhost) -1);
400 else
401 *res = '\0';
402 editedhost[sizeof editedhost - 1] = '\0';
403}
404
405static char *putlocation;
406
407 void
408putstr(s)
409 register char *s;
410{
411
412 while (*s)
413 putchr(*s++);
414}
415
416 void
417putchr(cc)
418 int cc;
419{
420 *putlocation++ = cc;
421}
422
423#ifdef __FreeBSD__
424static char fmtstr[] = { "%+" };
425#else
426/*
427 * This is split on two lines so that SCCS will not see the M
428 * between two % signs and expand it...
429 */
430static char fmtstr[] = { "%l:%M\
431%P on %A, %d %B %Y" };
432#endif
433
434 void
435putf(cp, where)
436 register char *cp;
437 char *where;
438{
439 char *slash;
440 time_t t;
441 char db[100];
441#ifdef STREAMSPTY
442 extern char *strchr();
443#else
444 extern char *strrchr();
445#endif
446#ifdef __FreeBSD__
447 static struct utsname kerninfo;
448
449 if (!*kerninfo.sysname)
450 uname(&kerninfo);
451#endif
452
453 putlocation = where;
454
455 while (*cp) {
456 if (*cp =='\n') {
457 putstr("\r\n");
458 cp++;
459 continue;
460 } else if (*cp != '%') {
461 putchr(*cp++);
462 continue;
463 }
464 switch (*++cp) {
465
466 case 't':
467#ifdef STREAMSPTY
468 /* names are like /dev/pts/2 -- we want pts/2 */
469 slash = strchr(line+1, '/');
470#else
471 slash = strrchr(line, '/');
472#endif
473 if (slash == (char *) 0)
474 putstr(line);
475 else
476 putstr(&slash[1]);
477 break;
478
479 case 'h':
480 putstr(editedhost);
481 break;
482
483 case 'd':
484#ifdef __FreeBSD__
485 setlocale(LC_TIME, "");
486#endif
487 (void)time(&t);
488 (void)strftime(db, sizeof(db), fmtstr, localtime(&t));
489 putstr(db);
490 break;
491
492#ifdef __FreeBSD__
493 case 's':
494 putstr(kerninfo.sysname);
495 break;
496
497 case 'm':
498 putstr(kerninfo.machine);
499 break;
500
501 case 'r':
502 putstr(kerninfo.release);
503 break;
504
505 case 'v':
506 putstr(kerninfo.version);
507 break;
508#endif
509
510 case '%':
511 putchr('%');
512 break;
513 }
514 cp++;
515 }
516}
517
518#ifdef DIAGNOSTICS
519/*
520 * Print telnet options and commands in plain text, if possible.
521 */
522 void
523printoption(fmt, option)
524 register char *fmt;
525 register int option;
526{
527 if (TELOPT_OK(option))
528 output_data("%s %s\r\n", fmt, TELOPT(option));
529 else if (TELCMD_OK(option))
530 output_data("%s %s\r\n", fmt, TELCMD(option));
531 else
532 output_data("%s %d\r\n", fmt, option);
533 return;
534}
535
536 void
537printsub(direction, pointer, length)
538 char direction; /* '<' or '>' */
539 unsigned char *pointer; /* where suboption data sits */
540 int length; /* length of suboption data */
541{
542 register int i = 0;
543
544 if (!(diagnostic & TD_OPTIONS))
545 return;
546
547 if (direction) {
548 output_data("td: %s suboption ",
549 direction == '<' ? "recv" : "send");
550 if (length >= 3) {
551 register int j;
552
553 i = pointer[length-2];
554 j = pointer[length-1];
555
556 if (i != IAC || j != SE) {
557 output_data("(terminated by ");
558 if (TELOPT_OK(i))
559 output_data("%s ", TELOPT(i));
560 else if (TELCMD_OK(i))
561 output_data("%s ", TELCMD(i));
562 else
563 output_data("%d ", i);
564 if (TELOPT_OK(j))
565 output_data("%s", TELOPT(j));
566 else if (TELCMD_OK(j))
567 output_data("%s", TELCMD(j));
568 else
569 output_data("%d", j);
570 output_data(", not IAC SE!) ");
571 }
572 }
573 length -= 2;
574 }
575 if (length < 1) {
576 output_data("(Empty suboption??\?)");
577 return;
578 }
579 switch (pointer[0]) {
580 case TELOPT_TTYPE:
581 output_data("TERMINAL-TYPE ");
582 switch (pointer[1]) {
583 case TELQUAL_IS:
584 output_data("IS \"%.*s\"", length-2, (char *)pointer+2);
585 break;
586 case TELQUAL_SEND:
587 output_data("SEND");
588 break;
589 default:
590 output_data(
591 "- unknown qualifier %d (0x%x).",
592 pointer[1], pointer[1]);
593 }
594 break;
595 case TELOPT_TSPEED:
596 output_data("TERMINAL-SPEED");
597 if (length < 2) {
598 output_data(" (empty suboption??\?)");
599 break;
600 }
601 switch (pointer[1]) {
602 case TELQUAL_IS:
603 output_data(" IS %.*s", length-2, (char *)pointer+2);
604 break;
605 default:
606 if (pointer[1] == 1)
607 output_data(" SEND");
608 else
609 output_data(" %d (unknown)", pointer[1]);
610 for (i = 2; i < length; i++) {
611 output_data(" ?%d?", pointer[i]);
612 }
613 break;
614 }
615 break;
616
617 case TELOPT_LFLOW:
618 output_data("TOGGLE-FLOW-CONTROL");
619 if (length < 2) {
620 output_data(" (empty suboption??\?)");
621 break;
622 }
623 switch (pointer[1]) {
624 case LFLOW_OFF:
625 output_data(" OFF"); break;
626 case LFLOW_ON:
627 output_data(" ON"); break;
628 case LFLOW_RESTART_ANY:
629 output_data(" RESTART-ANY"); break;
630 case LFLOW_RESTART_XON:
631 output_data(" RESTART-XON"); break;
632 default:
633 output_data(" %d (unknown)", pointer[1]);
634 }
635 for (i = 2; i < length; i++) {
636 output_data(" ?%d?", pointer[i]);
637 }
638 break;
639
640 case TELOPT_NAWS:
641 output_data("NAWS");
642 if (length < 2) {
643 output_data(" (empty suboption??\?)");
644 break;
645 }
646 if (length == 2) {
647 output_data(" ?%d?", pointer[1]);
648 break;
649 }
650 output_data(" %d %d (%d)",
651 pointer[1], pointer[2],
652 (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
653 if (length == 4) {
654 output_data(" ?%d?", pointer[3]);
655 break;
656 }
657 output_data(" %d %d (%d)",
658 pointer[3], pointer[4],
659 (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
660 for (i = 5; i < length; i++) {
661 output_data(" ?%d?", pointer[i]);
662 }
663 break;
664
665 case TELOPT_LINEMODE:
666 output_data("LINEMODE ");
667 if (length < 2) {
668 output_data(" (empty suboption??\?)");
669 break;
670 }
671 switch (pointer[1]) {
672 case WILL:
673 output_data("WILL ");
674 goto common;
675 case WONT:
676 output_data("WONT ");
677 goto common;
678 case DO:
679 output_data("DO ");
680 goto common;
681 case DONT:
682 output_data("DONT ");
683 common:
684 if (length < 3) {
685 output_data("(no option??\?)");
686 break;
687 }
688 switch (pointer[2]) {
689 case LM_FORWARDMASK:
690 output_data("Forward Mask");
691 for (i = 3; i < length; i++) {
692 output_data(" %x", pointer[i]);
693 }
694 break;
695 default:
696 output_data("%d (unknown)", pointer[2]);
697 for (i = 3; i < length; i++) {
698 output_data(" %d", pointer[i]);
699 }
700 break;
701 }
702 break;
703
704 case LM_SLC:
705 output_data("SLC");
706 for (i = 2; i < length - 2; i += 3) {
707 if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
708 output_data(" %s", SLC_NAME(pointer[i+SLC_FUNC]));
709 else
710 output_data(" %d", pointer[i+SLC_FUNC]);
711 switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
712 case SLC_NOSUPPORT:
713 output_data(" NOSUPPORT"); break;
714 case SLC_CANTCHANGE:
715 output_data(" CANTCHANGE"); break;
716 case SLC_VARIABLE:
717 output_data(" VARIABLE"); break;
718 case SLC_DEFAULT:
719 output_data(" DEFAULT"); break;
720 }
721 output_data("%s%s%s",
722 pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
723 pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
724 pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
725 if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
726 SLC_FLUSHOUT| SLC_LEVELBITS)) {
727 output_data("(0x%x)", pointer[i+SLC_FLAGS]);
728 }
729 output_data(" %d;", pointer[i+SLC_VALUE]);
730 if ((pointer[i+SLC_VALUE] == IAC) &&
731 (pointer[i+SLC_VALUE+1] == IAC))
732 i++;
733 }
734 for (; i < length; i++) {
735 output_data(" ?%d?", pointer[i]);
736 }
737 break;
738
739 case LM_MODE:
740 output_data("MODE ");
741 if (length < 3) {
742 output_data("(no mode??\?)");
743 break;
744 }
745 {
746 char tbuf[32];
747 sprintf(tbuf, "%s%s%s%s%s",
748 pointer[2]&MODE_EDIT ? "|EDIT" : "",
749 pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
750 pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
751 pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
752 pointer[2]&MODE_ACK ? "|ACK" : "");
753 output_data("%s", tbuf[1] ? &tbuf[1] : "0");
754 }
755 if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) {
756 output_data(" (0x%x)", pointer[2]);
757 }
758 for (i = 3; i < length; i++) {
759 output_data(" ?0x%x?", pointer[i]);
760 }
761 break;
762 default:
763 output_data("%d (unknown)", pointer[1]);
764 for (i = 2; i < length; i++) {
765 output_data(" %d", pointer[i]);
766 }
767 }
768 break;
769
770 case TELOPT_STATUS: {
771 register char *cp;
772 register int j, k;
773
774 output_data("STATUS");
775
776 switch (pointer[1]) {
777 default:
778 if (pointer[1] == TELQUAL_SEND)
779 output_data(" SEND");
780 else
781 output_data(" %d (unknown)", pointer[1]);
782 for (i = 2; i < length; i++) {
783 output_data(" ?%d?", pointer[i]);
784 }
785 break;
786 case TELQUAL_IS:
787 output_data(" IS\r\n");
788
789 for (i = 2; i < length; i++) {
790 switch(pointer[i]) {
791 case DO: cp = "DO"; goto common2;
792 case DONT: cp = "DONT"; goto common2;
793 case WILL: cp = "WILL"; goto common2;
794 case WONT: cp = "WONT"; goto common2;
795 common2:
796 i++;
797 if (TELOPT_OK(pointer[i]))
798 output_data(" %s %s", cp, TELOPT(pointer[i]));
799 else
800 output_data(" %s %d", cp, pointer[i]);
801
802 output_data("\r\n");
803 break;
804
805 case SB:
806 output_data(" SB ");
807 i++;
808 j = k = i;
809 while (j < length) {
810 if (pointer[j] == SE) {
811 if (j+1 == length)
812 break;
813 if (pointer[j+1] == SE)
814 j++;
815 else
816 break;
817 }
818 pointer[k++] = pointer[j++];
819 }
820 printsub(0, &pointer[i], k - i);
821 if (i < length) {
822 output_data(" SE");
823 i = j;
824 } else
825 i = j - 1;
826
827 output_data("\r\n");
828
829 break;
830
831 default:
832 output_data(" %d", pointer[i]);
833 break;
834 }
835 }
836 break;
837 }
838 break;
839 }
840
841 case TELOPT_XDISPLOC:
842 output_data("X-DISPLAY-LOCATION ");
843 switch (pointer[1]) {
844 case TELQUAL_IS:
845 output_data("IS \"%.*s\"", length-2, (char *)pointer+2);
846 break;
847 case TELQUAL_SEND:
848 output_data("SEND");
849 break;
850 default:
851 output_data("- unknown qualifier %d (0x%x).",
852 pointer[1], pointer[1]);
853 }
854 break;
855
856 case TELOPT_NEW_ENVIRON:
857 output_data("NEW-ENVIRON ");
858 goto env_common1;
859 case TELOPT_OLD_ENVIRON:
860 output_data("OLD-ENVIRON");
861 env_common1:
862 switch (pointer[1]) {
863 case TELQUAL_IS:
864 output_data("IS ");
865 goto env_common;
866 case TELQUAL_SEND:
867 output_data("SEND ");
868 goto env_common;
869 case TELQUAL_INFO:
870 output_data("INFO ");
871 env_common:
872 {
873 register int noquote = 2;
874 for (i = 2; i < length; i++ ) {
875 switch (pointer[i]) {
876 case NEW_ENV_VAR:
877 output_data("\" VAR " + noquote);
878 noquote = 2;
879 break;
880
881 case NEW_ENV_VALUE:
882 output_data("\" VALUE " + noquote);
883 noquote = 2;
884 break;
885
886 case ENV_ESC:
887 output_data("\" ESC " + noquote);
888 noquote = 2;
889 break;
890
891 case ENV_USERVAR:
892 output_data("\" USERVAR " + noquote);
893 noquote = 2;
894 break;
895
896 default:
897 if (isprint(pointer[i]) && pointer[i] != '"') {
898 if (noquote) {
899 output_data("\"");
900 noquote = 0;
901 }
902 output_data("%c", pointer[i]);
903 } else {
904 output_data("\" %03o " + noquote,
905 pointer[i]);
906 noquote = 2;
907 }
908 break;
909 }
910 }
911 if (!noquote)
912 output_data("\"");
913 break;
914 }
915 }
916 break;
917
918#if defined(AUTHENTICATION)
919 case TELOPT_AUTHENTICATION:
920 output_data("AUTHENTICATION");
921
922 if (length < 2) {
923 output_data(" (empty suboption??\?)");
924 break;
925 }
926 switch (pointer[1]) {
927 case TELQUAL_REPLY:
928 case TELQUAL_IS:
929 output_data(" %s ", (pointer[1] == TELQUAL_IS) ?
930 "IS" : "REPLY");
931 if (AUTHTYPE_NAME_OK(pointer[2]))
932 output_data("%s ", AUTHTYPE_NAME(pointer[2]));
933 else
934 output_data("%d ", pointer[2]);
935 if (length < 3) {
936 output_data("(partial suboption??\?)");
937 break;
938 }
939 output_data("%s|%s",
940 ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
941 "CLIENT" : "SERVER",
942 ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
943 "MUTUAL" : "ONE-WAY");
944
945 {
946 char buf[512];
947 auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
948 output_data("%s", buf);
949 }
950 break;
951
952 case TELQUAL_SEND:
953 i = 2;
954 output_data(" SEND ");
955 while (i < length) {
956 if (AUTHTYPE_NAME_OK(pointer[i]))
957 output_data("%s ", AUTHTYPE_NAME(pointer[i]));
958 else
959 output_data("%d ", pointer[i]);
960 if (++i >= length) {
961 output_data("(partial suboption??\?)");
962 break;
963 }
964 output_data("%s|%s ",
965 ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
966 "CLIENT" : "SERVER",
967 ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
968 "MUTUAL" : "ONE-WAY");
969 ++i;
970 }
971 break;
972
973 case TELQUAL_NAME:
974 output_data(" NAME \"%.*s\"", length - 2, pointer + 2);
975 break;
976
977 default:
978 for (i = 2; i < length; i++) {
979 output_data(" ?%d?", pointer[i]);
980 }
981 break;
982 }
983 break;
984#endif
985
986#ifdef ENCRYPTION
987 case TELOPT_ENCRYPT:
988 output_data("ENCRYPT");
989 if (length < 2) {
990 output_data(" (empty suboption??\?)");
991 break;
992 }
993 switch (pointer[1]) {
994 case ENCRYPT_START:
995 output_data(" START");
996 break;
997
998 case ENCRYPT_END:
999 output_data(" END");
1000 break;
1001
1002 case ENCRYPT_REQSTART:
1003 output_data(" REQUEST-START");
1004 break;
1005
1006 case ENCRYPT_REQEND:
1007 output_data(" REQUEST-END");
1008 break;
1009
1010 case ENCRYPT_IS:
1011 case ENCRYPT_REPLY:
1012 output_data(" %s ", (pointer[1] == ENCRYPT_IS) ?
1013 "IS" : "REPLY");
1014 if (length < 3) {
1015 output_data(" (partial suboption??\?)");
1016 break;
1017 }
1018 if (ENCTYPE_NAME_OK(pointer[2]))
1019 output_data("%s ", ENCTYPE_NAME(pointer[2]));
1020 else
1021 output_data(" %d (unknown)", pointer[2]);
1022
1023 {
1024 char buf[512];
1025 encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
1026 output_data("%s", buf);
1027 }
1028 break;
1029
1030 case ENCRYPT_SUPPORT:
1031 i = 2;
1032 output_data(" SUPPORT ");
1033 while (i < length) {
1034 if (ENCTYPE_NAME_OK(pointer[i]))
1035 output_data("%s ", ENCTYPE_NAME(pointer[i]));
1036 else
1037 output_data("%d ", pointer[i]);
1038 i++;
1039 }
1040 break;
1041
1042 case ENCRYPT_ENC_KEYID:
1043 output_data(" ENC_KEYID");
1044 goto encommon;
1045
1046 case ENCRYPT_DEC_KEYID:
1047 output_data(" DEC_KEYID");
1048 goto encommon;
1049
1050 default:
1051 output_data(" %d (unknown)", pointer[1]);
1052 encommon:
1053 for (i = 2; i < length; i++) {
1054 output_data(" %d", pointer[i]);
1055 }
1056 break;
1057 }
1058 break;
1059#endif /* ENCRYPTION */
1060
1061 default:
1062 if (TELOPT_OK(pointer[0]))
1063 output_data("%s (unknown)", TELOPT(pointer[0]));
1064 else
1065 output_data("%d (unknown)", pointer[i]);
1066 for (i = 1; i < length; i++) {
1067 output_data(" %d", pointer[i]);
1068 }
1069 break;
1070 }
1071 output_data("\r\n");
1072}
1073
1074/*
1075 * Dump a data buffer in hex and ascii to the output data stream.
1076 */
1077 void
1078printdata(tag, ptr, cnt)
1079 register char *tag;
1080 register char *ptr;
1081 register int cnt;
1082{
1083 register int i;
1084 char xbuf[30];
1085
1086 while (cnt) {
1087 /* flush net output buffer if no room for new data) */
1088 if ((&netobuf[BUFSIZ] - nfrontp) < 80) {
1089 netflush();
1090 }
1091
1092 /* add a line of output */
1093 output_data("%s: ", tag);
1094 for (i = 0; i < 20 && cnt; i++) {
1095 output_data("%02x", *ptr);
1096 if (isprint(*ptr)) {
1097 xbuf[i] = *ptr;
1098 } else {
1099 xbuf[i] = '.';
1100 }
1101 if (i % 2) {
1102 output_data(" ");
1103 }
1104 cnt--;
1105 ptr++;
1106 }
1107 xbuf[i] = '\0';
1108 output_data(" %s\r\n", xbuf );
1109 }
1110}
1111#endif /* DIAGNOSTICS */
442#ifdef __FreeBSD__
443 static struct utsname kerninfo;
444
445 if (!*kerninfo.sysname)
446 uname(&kerninfo);
447#endif
448
449 putlocation = where;
450
451 while (*cp) {
452 if (*cp =='\n') {
453 putstr("\r\n");
454 cp++;
455 continue;
456 } else if (*cp != '%') {
457 putchr(*cp++);
458 continue;
459 }
460 switch (*++cp) {
461
462 case 't':
463#ifdef STREAMSPTY
464 /* names are like /dev/pts/2 -- we want pts/2 */
465 slash = strchr(line+1, '/');
466#else
467 slash = strrchr(line, '/');
468#endif
469 if (slash == (char *) 0)
470 putstr(line);
471 else
472 putstr(&slash[1]);
473 break;
474
475 case 'h':
476 putstr(editedhost);
477 break;
478
479 case 'd':
480#ifdef __FreeBSD__
481 setlocale(LC_TIME, "");
482#endif
483 (void)time(&t);
484 (void)strftime(db, sizeof(db), fmtstr, localtime(&t));
485 putstr(db);
486 break;
487
488#ifdef __FreeBSD__
489 case 's':
490 putstr(kerninfo.sysname);
491 break;
492
493 case 'm':
494 putstr(kerninfo.machine);
495 break;
496
497 case 'r':
498 putstr(kerninfo.release);
499 break;
500
501 case 'v':
502 putstr(kerninfo.version);
503 break;
504#endif
505
506 case '%':
507 putchr('%');
508 break;
509 }
510 cp++;
511 }
512}
513
514#ifdef DIAGNOSTICS
515/*
516 * Print telnet options and commands in plain text, if possible.
517 */
518 void
519printoption(fmt, option)
520 register char *fmt;
521 register int option;
522{
523 if (TELOPT_OK(option))
524 output_data("%s %s\r\n", fmt, TELOPT(option));
525 else if (TELCMD_OK(option))
526 output_data("%s %s\r\n", fmt, TELCMD(option));
527 else
528 output_data("%s %d\r\n", fmt, option);
529 return;
530}
531
532 void
533printsub(direction, pointer, length)
534 char direction; /* '<' or '>' */
535 unsigned char *pointer; /* where suboption data sits */
536 int length; /* length of suboption data */
537{
538 register int i = 0;
539
540 if (!(diagnostic & TD_OPTIONS))
541 return;
542
543 if (direction) {
544 output_data("td: %s suboption ",
545 direction == '<' ? "recv" : "send");
546 if (length >= 3) {
547 register int j;
548
549 i = pointer[length-2];
550 j = pointer[length-1];
551
552 if (i != IAC || j != SE) {
553 output_data("(terminated by ");
554 if (TELOPT_OK(i))
555 output_data("%s ", TELOPT(i));
556 else if (TELCMD_OK(i))
557 output_data("%s ", TELCMD(i));
558 else
559 output_data("%d ", i);
560 if (TELOPT_OK(j))
561 output_data("%s", TELOPT(j));
562 else if (TELCMD_OK(j))
563 output_data("%s", TELCMD(j));
564 else
565 output_data("%d", j);
566 output_data(", not IAC SE!) ");
567 }
568 }
569 length -= 2;
570 }
571 if (length < 1) {
572 output_data("(Empty suboption??\?)");
573 return;
574 }
575 switch (pointer[0]) {
576 case TELOPT_TTYPE:
577 output_data("TERMINAL-TYPE ");
578 switch (pointer[1]) {
579 case TELQUAL_IS:
580 output_data("IS \"%.*s\"", length-2, (char *)pointer+2);
581 break;
582 case TELQUAL_SEND:
583 output_data("SEND");
584 break;
585 default:
586 output_data(
587 "- unknown qualifier %d (0x%x).",
588 pointer[1], pointer[1]);
589 }
590 break;
591 case TELOPT_TSPEED:
592 output_data("TERMINAL-SPEED");
593 if (length < 2) {
594 output_data(" (empty suboption??\?)");
595 break;
596 }
597 switch (pointer[1]) {
598 case TELQUAL_IS:
599 output_data(" IS %.*s", length-2, (char *)pointer+2);
600 break;
601 default:
602 if (pointer[1] == 1)
603 output_data(" SEND");
604 else
605 output_data(" %d (unknown)", pointer[1]);
606 for (i = 2; i < length; i++) {
607 output_data(" ?%d?", pointer[i]);
608 }
609 break;
610 }
611 break;
612
613 case TELOPT_LFLOW:
614 output_data("TOGGLE-FLOW-CONTROL");
615 if (length < 2) {
616 output_data(" (empty suboption??\?)");
617 break;
618 }
619 switch (pointer[1]) {
620 case LFLOW_OFF:
621 output_data(" OFF"); break;
622 case LFLOW_ON:
623 output_data(" ON"); break;
624 case LFLOW_RESTART_ANY:
625 output_data(" RESTART-ANY"); break;
626 case LFLOW_RESTART_XON:
627 output_data(" RESTART-XON"); break;
628 default:
629 output_data(" %d (unknown)", pointer[1]);
630 }
631 for (i = 2; i < length; i++) {
632 output_data(" ?%d?", pointer[i]);
633 }
634 break;
635
636 case TELOPT_NAWS:
637 output_data("NAWS");
638 if (length < 2) {
639 output_data(" (empty suboption??\?)");
640 break;
641 }
642 if (length == 2) {
643 output_data(" ?%d?", pointer[1]);
644 break;
645 }
646 output_data(" %d %d (%d)",
647 pointer[1], pointer[2],
648 (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
649 if (length == 4) {
650 output_data(" ?%d?", pointer[3]);
651 break;
652 }
653 output_data(" %d %d (%d)",
654 pointer[3], pointer[4],
655 (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
656 for (i = 5; i < length; i++) {
657 output_data(" ?%d?", pointer[i]);
658 }
659 break;
660
661 case TELOPT_LINEMODE:
662 output_data("LINEMODE ");
663 if (length < 2) {
664 output_data(" (empty suboption??\?)");
665 break;
666 }
667 switch (pointer[1]) {
668 case WILL:
669 output_data("WILL ");
670 goto common;
671 case WONT:
672 output_data("WONT ");
673 goto common;
674 case DO:
675 output_data("DO ");
676 goto common;
677 case DONT:
678 output_data("DONT ");
679 common:
680 if (length < 3) {
681 output_data("(no option??\?)");
682 break;
683 }
684 switch (pointer[2]) {
685 case LM_FORWARDMASK:
686 output_data("Forward Mask");
687 for (i = 3; i < length; i++) {
688 output_data(" %x", pointer[i]);
689 }
690 break;
691 default:
692 output_data("%d (unknown)", pointer[2]);
693 for (i = 3; i < length; i++) {
694 output_data(" %d", pointer[i]);
695 }
696 break;
697 }
698 break;
699
700 case LM_SLC:
701 output_data("SLC");
702 for (i = 2; i < length - 2; i += 3) {
703 if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
704 output_data(" %s", SLC_NAME(pointer[i+SLC_FUNC]));
705 else
706 output_data(" %d", pointer[i+SLC_FUNC]);
707 switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
708 case SLC_NOSUPPORT:
709 output_data(" NOSUPPORT"); break;
710 case SLC_CANTCHANGE:
711 output_data(" CANTCHANGE"); break;
712 case SLC_VARIABLE:
713 output_data(" VARIABLE"); break;
714 case SLC_DEFAULT:
715 output_data(" DEFAULT"); break;
716 }
717 output_data("%s%s%s",
718 pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
719 pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
720 pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
721 if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
722 SLC_FLUSHOUT| SLC_LEVELBITS)) {
723 output_data("(0x%x)", pointer[i+SLC_FLAGS]);
724 }
725 output_data(" %d;", pointer[i+SLC_VALUE]);
726 if ((pointer[i+SLC_VALUE] == IAC) &&
727 (pointer[i+SLC_VALUE+1] == IAC))
728 i++;
729 }
730 for (; i < length; i++) {
731 output_data(" ?%d?", pointer[i]);
732 }
733 break;
734
735 case LM_MODE:
736 output_data("MODE ");
737 if (length < 3) {
738 output_data("(no mode??\?)");
739 break;
740 }
741 {
742 char tbuf[32];
743 sprintf(tbuf, "%s%s%s%s%s",
744 pointer[2]&MODE_EDIT ? "|EDIT" : "",
745 pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
746 pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
747 pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
748 pointer[2]&MODE_ACK ? "|ACK" : "");
749 output_data("%s", tbuf[1] ? &tbuf[1] : "0");
750 }
751 if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) {
752 output_data(" (0x%x)", pointer[2]);
753 }
754 for (i = 3; i < length; i++) {
755 output_data(" ?0x%x?", pointer[i]);
756 }
757 break;
758 default:
759 output_data("%d (unknown)", pointer[1]);
760 for (i = 2; i < length; i++) {
761 output_data(" %d", pointer[i]);
762 }
763 }
764 break;
765
766 case TELOPT_STATUS: {
767 register char *cp;
768 register int j, k;
769
770 output_data("STATUS");
771
772 switch (pointer[1]) {
773 default:
774 if (pointer[1] == TELQUAL_SEND)
775 output_data(" SEND");
776 else
777 output_data(" %d (unknown)", pointer[1]);
778 for (i = 2; i < length; i++) {
779 output_data(" ?%d?", pointer[i]);
780 }
781 break;
782 case TELQUAL_IS:
783 output_data(" IS\r\n");
784
785 for (i = 2; i < length; i++) {
786 switch(pointer[i]) {
787 case DO: cp = "DO"; goto common2;
788 case DONT: cp = "DONT"; goto common2;
789 case WILL: cp = "WILL"; goto common2;
790 case WONT: cp = "WONT"; goto common2;
791 common2:
792 i++;
793 if (TELOPT_OK(pointer[i]))
794 output_data(" %s %s", cp, TELOPT(pointer[i]));
795 else
796 output_data(" %s %d", cp, pointer[i]);
797
798 output_data("\r\n");
799 break;
800
801 case SB:
802 output_data(" SB ");
803 i++;
804 j = k = i;
805 while (j < length) {
806 if (pointer[j] == SE) {
807 if (j+1 == length)
808 break;
809 if (pointer[j+1] == SE)
810 j++;
811 else
812 break;
813 }
814 pointer[k++] = pointer[j++];
815 }
816 printsub(0, &pointer[i], k - i);
817 if (i < length) {
818 output_data(" SE");
819 i = j;
820 } else
821 i = j - 1;
822
823 output_data("\r\n");
824
825 break;
826
827 default:
828 output_data(" %d", pointer[i]);
829 break;
830 }
831 }
832 break;
833 }
834 break;
835 }
836
837 case TELOPT_XDISPLOC:
838 output_data("X-DISPLAY-LOCATION ");
839 switch (pointer[1]) {
840 case TELQUAL_IS:
841 output_data("IS \"%.*s\"", length-2, (char *)pointer+2);
842 break;
843 case TELQUAL_SEND:
844 output_data("SEND");
845 break;
846 default:
847 output_data("- unknown qualifier %d (0x%x).",
848 pointer[1], pointer[1]);
849 }
850 break;
851
852 case TELOPT_NEW_ENVIRON:
853 output_data("NEW-ENVIRON ");
854 goto env_common1;
855 case TELOPT_OLD_ENVIRON:
856 output_data("OLD-ENVIRON");
857 env_common1:
858 switch (pointer[1]) {
859 case TELQUAL_IS:
860 output_data("IS ");
861 goto env_common;
862 case TELQUAL_SEND:
863 output_data("SEND ");
864 goto env_common;
865 case TELQUAL_INFO:
866 output_data("INFO ");
867 env_common:
868 {
869 register int noquote = 2;
870 for (i = 2; i < length; i++ ) {
871 switch (pointer[i]) {
872 case NEW_ENV_VAR:
873 output_data("\" VAR " + noquote);
874 noquote = 2;
875 break;
876
877 case NEW_ENV_VALUE:
878 output_data("\" VALUE " + noquote);
879 noquote = 2;
880 break;
881
882 case ENV_ESC:
883 output_data("\" ESC " + noquote);
884 noquote = 2;
885 break;
886
887 case ENV_USERVAR:
888 output_data("\" USERVAR " + noquote);
889 noquote = 2;
890 break;
891
892 default:
893 if (isprint(pointer[i]) && pointer[i] != '"') {
894 if (noquote) {
895 output_data("\"");
896 noquote = 0;
897 }
898 output_data("%c", pointer[i]);
899 } else {
900 output_data("\" %03o " + noquote,
901 pointer[i]);
902 noquote = 2;
903 }
904 break;
905 }
906 }
907 if (!noquote)
908 output_data("\"");
909 break;
910 }
911 }
912 break;
913
914#if defined(AUTHENTICATION)
915 case TELOPT_AUTHENTICATION:
916 output_data("AUTHENTICATION");
917
918 if (length < 2) {
919 output_data(" (empty suboption??\?)");
920 break;
921 }
922 switch (pointer[1]) {
923 case TELQUAL_REPLY:
924 case TELQUAL_IS:
925 output_data(" %s ", (pointer[1] == TELQUAL_IS) ?
926 "IS" : "REPLY");
927 if (AUTHTYPE_NAME_OK(pointer[2]))
928 output_data("%s ", AUTHTYPE_NAME(pointer[2]));
929 else
930 output_data("%d ", pointer[2]);
931 if (length < 3) {
932 output_data("(partial suboption??\?)");
933 break;
934 }
935 output_data("%s|%s",
936 ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
937 "CLIENT" : "SERVER",
938 ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
939 "MUTUAL" : "ONE-WAY");
940
941 {
942 char buf[512];
943 auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
944 output_data("%s", buf);
945 }
946 break;
947
948 case TELQUAL_SEND:
949 i = 2;
950 output_data(" SEND ");
951 while (i < length) {
952 if (AUTHTYPE_NAME_OK(pointer[i]))
953 output_data("%s ", AUTHTYPE_NAME(pointer[i]));
954 else
955 output_data("%d ", pointer[i]);
956 if (++i >= length) {
957 output_data("(partial suboption??\?)");
958 break;
959 }
960 output_data("%s|%s ",
961 ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
962 "CLIENT" : "SERVER",
963 ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
964 "MUTUAL" : "ONE-WAY");
965 ++i;
966 }
967 break;
968
969 case TELQUAL_NAME:
970 output_data(" NAME \"%.*s\"", length - 2, pointer + 2);
971 break;
972
973 default:
974 for (i = 2; i < length; i++) {
975 output_data(" ?%d?", pointer[i]);
976 }
977 break;
978 }
979 break;
980#endif
981
982#ifdef ENCRYPTION
983 case TELOPT_ENCRYPT:
984 output_data("ENCRYPT");
985 if (length < 2) {
986 output_data(" (empty suboption??\?)");
987 break;
988 }
989 switch (pointer[1]) {
990 case ENCRYPT_START:
991 output_data(" START");
992 break;
993
994 case ENCRYPT_END:
995 output_data(" END");
996 break;
997
998 case ENCRYPT_REQSTART:
999 output_data(" REQUEST-START");
1000 break;
1001
1002 case ENCRYPT_REQEND:
1003 output_data(" REQUEST-END");
1004 break;
1005
1006 case ENCRYPT_IS:
1007 case ENCRYPT_REPLY:
1008 output_data(" %s ", (pointer[1] == ENCRYPT_IS) ?
1009 "IS" : "REPLY");
1010 if (length < 3) {
1011 output_data(" (partial suboption??\?)");
1012 break;
1013 }
1014 if (ENCTYPE_NAME_OK(pointer[2]))
1015 output_data("%s ", ENCTYPE_NAME(pointer[2]));
1016 else
1017 output_data(" %d (unknown)", pointer[2]);
1018
1019 {
1020 char buf[512];
1021 encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
1022 output_data("%s", buf);
1023 }
1024 break;
1025
1026 case ENCRYPT_SUPPORT:
1027 i = 2;
1028 output_data(" SUPPORT ");
1029 while (i < length) {
1030 if (ENCTYPE_NAME_OK(pointer[i]))
1031 output_data("%s ", ENCTYPE_NAME(pointer[i]));
1032 else
1033 output_data("%d ", pointer[i]);
1034 i++;
1035 }
1036 break;
1037
1038 case ENCRYPT_ENC_KEYID:
1039 output_data(" ENC_KEYID");
1040 goto encommon;
1041
1042 case ENCRYPT_DEC_KEYID:
1043 output_data(" DEC_KEYID");
1044 goto encommon;
1045
1046 default:
1047 output_data(" %d (unknown)", pointer[1]);
1048 encommon:
1049 for (i = 2; i < length; i++) {
1050 output_data(" %d", pointer[i]);
1051 }
1052 break;
1053 }
1054 break;
1055#endif /* ENCRYPTION */
1056
1057 default:
1058 if (TELOPT_OK(pointer[0]))
1059 output_data("%s (unknown)", TELOPT(pointer[0]));
1060 else
1061 output_data("%d (unknown)", pointer[i]);
1062 for (i = 1; i < length; i++) {
1063 output_data(" %d", pointer[i]);
1064 }
1065 break;
1066 }
1067 output_data("\r\n");
1068}
1069
1070/*
1071 * Dump a data buffer in hex and ascii to the output data stream.
1072 */
1073 void
1074printdata(tag, ptr, cnt)
1075 register char *tag;
1076 register char *ptr;
1077 register int cnt;
1078{
1079 register int i;
1080 char xbuf[30];
1081
1082 while (cnt) {
1083 /* flush net output buffer if no room for new data) */
1084 if ((&netobuf[BUFSIZ] - nfrontp) < 80) {
1085 netflush();
1086 }
1087
1088 /* add a line of output */
1089 output_data("%s: ", tag);
1090 for (i = 0; i < 20 && cnt; i++) {
1091 output_data("%02x", *ptr);
1092 if (isprint(*ptr)) {
1093 xbuf[i] = *ptr;
1094 } else {
1095 xbuf[i] = '.';
1096 }
1097 if (i % 2) {
1098 output_data(" ");
1099 }
1100 cnt--;
1101 ptr++;
1102 }
1103 xbuf[i] = '\0';
1104 output_data(" %s\r\n", xbuf );
1105 }
1106}
1107#endif /* DIAGNOSTICS */