Bug Summary

File:src/usr.bin/telnet/commands.c
Warning:line 1803, column 2
Potential leak of memory pointed to by 'user'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name commands.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/telnet/obj -resource-dir /usr/local/lib/clang/13.0.0 -D KLUDGELINEMODE -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/telnet/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/telnet/commands.c
1/* $OpenBSD: commands.c,v 1.87 2019/06/28 13:35:04 deraadt Exp $ */
2/* $NetBSD: commands.c,v 1.14 1996/03/24 22:03:48 jtk Exp $ */
3
4/*
5 * Copyright (c) 1988, 1990, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include "telnet_locl.h"
34
35#include <sys/socket.h>
36#include <netinet/in.h>
37#include <netinet/ip.h>
38#include <arpa/inet.h>
39#include <arpa/telnet.h>
40
41#include <ctype.h>
42#include <err.h>
43#include <errno(*__errno()).h>
44#include <netdb.h>
45#include <pwd.h>
46#include <stdarg.h>
47#include <stdlib.h>
48#include <string.h>
49#include <unistd.h>
50#include <limits.h>
51
52char *hostname;
53
54typedef struct {
55 char *name; /* command name */
56 char *help; /* help string (NULL for no help) */
57 int (*handler)(int, char **);/* routine which executes command */
58 int needconnect; /* Do we need to be connected to execute? */
59} Command;
60
61#define MAXARGV20 20
62
63static char line[256];
64static int margc;
65static char *margv[MAXARGV20+1];
66
67static int
68makeargv(void)
69{
70 char *cp, *cp2, c;
71 char **argp = margv;
72 int ret = 0;
73
74 margc = 0;
75 cp = line;
76 while ((c = *cp)) {
77 if (margc >= MAXARGV20) {
78 printf("too many arguments\n");
79 ret = 1;
80 break;
81 }
82 int inquote = 0;
83 while (isspace((unsigned char)c))
84 c = *++cp;
85 if (c == '\0')
86 break;
87 *argp++ = cp;
88 margc += 1;
89 for (cp2 = cp; c != '\0'; c = *++cp) {
90 if (inquote) {
91 if (c == inquote) {
92 inquote = 0;
93 continue;
94 }
95 } else {
96 if (c == '\\') {
97 if ((c = *++cp) == '\0')
98 break;
99 } else if (c == '"') {
100 inquote = '"';
101 continue;
102 } else if (c == '\'') {
103 inquote = '\'';
104 continue;
105 } else if (isspace((unsigned char)c))
106 break;
107 }
108 *cp2++ = c;
109 }
110 *cp2 = '\0';
111 if (c == '\0')
112 break;
113 cp++;
114 }
115 *argp++ = 0;
116 return (ret);
117}
118
119/*
120 * Make a character string into a number.
121 *
122 * Todo: 1. Could take random integers (12, 0x12, 012, 0b1).
123 */
124
125static char
126special(char *s)
127{
128 char c;
129 char b;
130
131 switch (*s) {
132 case '^':
133 b = *++s;
134 if (b == '?') {
135 c = b | 0x40; /* DEL */
136 } else {
137 c = b & 0x1f;
138 }
139 break;
140 default:
141 c = *s;
142 break;
143 }
144 return c;
145}
146
147/*
148 * Construct a control character sequence
149 * for a special character.
150 */
151static char *
152control(cc_t c)
153{
154 static char buf[5];
155 /*
156 * The only way I could get the Sun 3.5 compiler
157 * to shut up about
158 * if ((unsigned int)c >= 0x80)
159 * was to assign "c" to an unsigned int variable...
160 * Arggg....
161 */
162 unsigned int uic = (unsigned int)c;
163
164 if (uic == 0x7f)
165 return ("^?");
166 if (c == (cc_t)_POSIX_VDISABLE(0377)) {
167 return "off";
168 }
169 if (uic >= 0x80) {
170 buf[0] = '\\';
171 buf[1] = ((c>>6)&07) + '0';
172 buf[2] = ((c>>3)&07) + '0';
173 buf[3] = (c&07) + '0';
174 buf[4] = 0;
175 } else if (uic >= 0x20) {
176 buf[0] = c;
177 buf[1] = 0;
178 } else {
179 buf[0] = '^';
180 buf[1] = '@'+c;
181 buf[2] = 0;
182 }
183 return (buf);
184}
185
186/*
187 * The following are data structures and routines for
188 * the "send" command.
189 *
190 */
191
192struct sendlist {
193 char *name; /* How user refers to it (case independent) */
194 char *help; /* Help information (0 ==> no help) */
195 int needconnect; /* Need to be connected */
196 int narg; /* Number of arguments */
197 int (*handler)(); /* Routine to perform (for special ops) */
198 int nbyte; /* Number of bytes to send this command */
199 int what; /* Character to be sent (<0 ==> special) */
200};
201
202
203static int
204 send_esc(void),
205 send_help(void),
206 send_docmd(char *),
207 send_dontcmd(char *),
208 send_willcmd(char *),
209 send_wontcmd(char *);
210
211static struct sendlist Sendlist[] = {
212 { "ao", "Send Telnet Abort output", 1, 0, 0, 2, AO245 },
213 { "ayt", "Send Telnet 'Are You There'", 1, 0, 0, 2, AYT246 },
214 { "brk", "Send Telnet Break", 1, 0, 0, 2, BREAK243 },
215 { "break", 0, 1, 0, 0, 2, BREAK243 },
216 { "ec", "Send Telnet Erase Character", 1, 0, 0, 2, EC247 },
217 { "el", "Send Telnet Erase Line", 1, 0, 0, 2, EL248 },
218 { "escape", "Send current escape character", 1, 0, send_esc, 1, 0 },
219 { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, 0, 2, GA249 },
220 { "ip", "Send Telnet Interrupt Process", 1, 0, 0, 2, IP244 },
221 { "intp", 0, 1, 0, 0, 2, IP244 },
222 { "interrupt", 0, 1, 0, 0, 2, IP244 },
223 { "intr", 0, 1, 0, 0, 2, IP244 },
224 { "nop", "Send Telnet 'No operation'", 1, 0, 0, 2, NOP241 },
225 { "eor", "Send Telnet 'End of Record'", 1, 0, 0, 2, EOR239 },
226 { "abort", "Send Telnet 'Abort Process'", 1, 0, 0, 2, ABORT238 },
227 { "susp", "Send Telnet 'Suspend Process'", 1, 0, 0, 2, SUSP237 },
228 { "eof", "Send Telnet End of File Character", 1, 0, 0, 2, xEOF236 },
229 { "synch", "Perform Telnet 'Synch operation'", 1, 0, dosynch, 2, 0 },
230 { "getstatus", "Send request for STATUS", 1, 0, get_status, 6, 0 },
231 { "?", "Display send options", 0, 0, send_help, 0, 0 },
232 { "help", 0, 0, 0, send_help, 0, 0 },
233 { "do", 0, 0, 1, send_docmd, 3, 0 },
234 { "dont", 0, 0, 1, send_dontcmd, 3, 0 },
235 { "will", 0, 0, 1, send_willcmd, 3, 0 },
236 { "wont", 0, 0, 1, send_wontcmd, 3, 0 },
237 { 0 }
238};
239
240#define GETSEND(name)((struct sendlist *) genget(name, (char **) Sendlist, sizeof(
struct sendlist)))
((struct sendlist *) genget(name, (char **) Sendlist, \
241 sizeof(struct sendlist)))
242
243static int
244sendcmd(int argc, char **argv)
245{
246 int count; /* how many bytes we are going to need to send */
247 int i;
248 struct sendlist *s; /* pointer to current command */
249 int success = 0;
250 int needconnect = 0;
251
252 if (argc < 2) {
253 printf("need at least one argument for 'send' command\r\n");
254 printf("'send ?' for help\r\n");
255 return 0;
256 }
257 /*
258 * First, validate all the send arguments.
259 * In addition, we see how much space we are going to need, and
260 * whether or not we will be doing a "SYNCH" operation (which
261 * flushes the network queue).
262 */
263 count = 0;
264 for (i = 1; i < argc; i++) {
265 s = GETSEND(argv[i])((struct sendlist *) genget(argv[i], (char **) Sendlist, sizeof
(struct sendlist)))
;
266 if (s == 0) {
267 printf("Unknown send argument '%s'\r\n'send ?' for help.\r\n",
268 argv[i]);
269 return 0;
270 } else if (Ambiguous(s)) {
271 printf("Ambiguous send argument '%s'\r\n'send ?' for help.\r\n",
272 argv[i]);
273 return 0;
274 }
275 if (i + s->narg >= argc) {
276 fprintf(stderr(&__sF[2]),
277 "Need %d argument%s to 'send %s' command. 'send %s ?' for help.\r\n",
278 s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
279 return 0;
280 }
281 count += s->nbyte;
282 if (s->handler == send_help) {
283 send_help();
284 return 0;
285 }
286
287 i += s->narg;
288 needconnect += s->needconnect;
289 }
290 if (!connected && needconnect) {
291 printf("?Need to be connected first.\r\n");
292 printf("'send ?' for help\r\n");
293 return 0;
294 }
295 /* Now, do we have enough room? */
296 if (NETROOM()(ring_empty_count(&netoring)) < count) {
297 printf("There is not enough room in the buffer TO the network\r\n");
298 printf("to process your request. Nothing will be done.\r\n");
299 printf("('send synch' will throw away most data in the network\r\n");
300 printf("buffer, if this might help.)\r\n");
301 return 0;
302 }
303 /* OK, they are all OK, now go through again and actually send */
304 count = 0;
305 for (i = 1; i < argc; i++) {
306 if ((s = GETSEND(argv[i])((struct sendlist *) genget(argv[i], (char **) Sendlist, sizeof
(struct sendlist)))
) == 0) {
307 fprintf(stderr(&__sF[2]), "Telnet 'send' error - argument disappeared!\r\n");
308 quit();
309 }
310 if (s->handler) {
311 count++;
312 success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0,
313 (s->narg > 1) ? argv[i+2] : 0);
314 i += s->narg;
315 } else {
316 NET2ADD(IAC, s->what){ { *netoring.supply = 255; ring_supplied(&netoring, 1); }
; { *netoring.supply = s->what; ring_supplied(&netoring
, 1); }; }
;
317 printoption("SENT", IAC255, s->what);
318 }
319 }
320 return (count == success);
321}
322
323static int send_tncmd(void (*func)(int, int), char *cmd, char *name);
324
325static int
326send_esc(void)
327{
328 NETADD(escape){ *netoring.supply = escape; ring_supplied(&netoring, 1);
}
;
329 return 1;
330}
331
332static int
333send_docmd(char *name)
334{
335 return(send_tncmd(send_do, "do", name));
336}
337
338static int
339send_dontcmd(char *name)
340{
341 return(send_tncmd(send_dont, "dont", name));
342}
343
344static int
345send_willcmd(char *name)
346{
347 return(send_tncmd(send_will, "will", name));
348}
349
350static int
351send_wontcmd(char *name)
352{
353 return(send_tncmd(send_wont, "wont", name));
354}
355
356int
357send_tncmd(void (*func)(int, int), char *cmd, char *name)
358{
359 char **cpp;
360 extern char *telopts[];
361 int val = 0;
362
363 if (isprefix(name, "help") || isprefix(name, "?")) {
364 int col, len;
365
366 printf("Usage: send %s <value|option>\r\n", cmd);
367 printf("\"value\" must be from 0 to 255\r\n");
368 printf("Valid options are:\r\n\t");
369
370 col = 8;
371 for (cpp = telopts; *cpp; cpp++) {
372 len = strlen(*cpp) + 3;
373 if (col + len > 65) {
374 printf("\r\n\t");
375 col = 8;
376 }
377 printf(" \"%s\"", *cpp);
378 col += len;
379 }
380 printf("\r\n");
381 return 0;
382 }
383 cpp = (char **)genget(name, telopts, sizeof(char *));
384 if (Ambiguous(cpp)) {
385 fprintf(stderr(&__sF[2]),"'%s': ambiguous argument ('send %s ?' for help).\r\n",
386 name, cmd);
387 return 0;
388 }
389 if (cpp) {
390 val = cpp - telopts;
391 } else {
392 char *cp = name;
393
394 while (*cp >= '0' && *cp <= '9') {
395 val *= 10;
396 val += *cp - '0';
397 cp++;
398 }
399 if (*cp != 0) {
400 fprintf(stderr(&__sF[2]), "'%s': unknown argument ('send %s ?' for help).\r\n",
401 name, cmd);
402 return 0;
403 } else if (val < 0 || val > 255) {
404 fprintf(stderr(&__sF[2]), "'%s': bad value ('send %s ?' for help).\r\n",
405 name, cmd);
406 return 0;
407 }
408 }
409 if (!connected) {
410 printf("?Need to be connected first.\r\n");
411 return 0;
412 }
413 (*func)(val, 1);
414 return 1;
415}
416
417static int
418send_help(void)
419{
420 struct sendlist *s; /* pointer to current command */
421 for (s = Sendlist; s->name; s++) {
422 if (s->help)
423 printf("%-15s %s\r\n", s->name, s->help);
424 }
425 return(0);
426}
427
428/*
429 * The following are the routines and data structures referred
430 * to by the arguments to the "toggle" command.
431 */
432
433static int
434lclchars(int unused)
435{
436 donelclchars = 1;
437 return 1;
438}
439
440static int
441togcrlf(int unused)
442{
443 if (crlf) {
444 printf("Will send carriage returns as telnet <CR><LF>.\r\n");
445 } else {
446 printf("Will send carriage returns as telnet <CR><NUL>.\r\n");
447 }
448 return 1;
449}
450
451int binmode;
452
453static int
454togbinary(int val)
455{
456 donebinarytoggle = 1;
457
458 if (val >= 0) {
459 binmode = val;
460 } else {
461 if (my_want_state_is_will(TELOPT_BINARY)(options[0]&0x02) &&
462 my_want_state_is_do(TELOPT_BINARY)(options[0]&0x08)) {
463 binmode = 1;
464 } else if (my_want_state_is_wont(TELOPT_BINARY)(!(options[0]&0x02)) &&
465 my_want_state_is_dont(TELOPT_BINARY)(!(options[0]&0x08))) {
466 binmode = 0;
467 }
468 val = binmode ? 0 : 1;
469 }
470
471 if (val == 1) {
472 if (my_want_state_is_will(TELOPT_BINARY)(options[0]&0x02) &&
473 my_want_state_is_do(TELOPT_BINARY)(options[0]&0x08)) {
474 printf("Already operating in binary mode with remote host.\r\n");
475 } else {
476 printf("Negotiating binary mode with remote host.\r\n");
477 tel_enter_binary(3);
478 }
479 } else {
480 if (my_want_state_is_wont(TELOPT_BINARY)(!(options[0]&0x02)) &&
481 my_want_state_is_dont(TELOPT_BINARY)(!(options[0]&0x08))) {
482 printf("Already in network ascii mode with remote host.\r\n");
483 } else {
484 printf("Negotiating network ascii mode with remote host.\r\n");
485 tel_leave_binary(3);
486 }
487 }
488 return 1;
489}
490
491static int
492togrbinary(int val)
493{
494 donebinarytoggle = 1;
495
496 if (val == -1)
497 val = my_want_state_is_do(TELOPT_BINARY)(options[0]&0x08) ? 0 : 1;
498
499 if (val == 1) {
500 if (my_want_state_is_do(TELOPT_BINARY)(options[0]&0x08)) {
501 printf("Already receiving in binary mode.\r\n");
502 } else {
503 printf("Negotiating binary mode on input.\r\n");
504 tel_enter_binary(1);
505 }
506 } else {
507 if (my_want_state_is_dont(TELOPT_BINARY)(!(options[0]&0x08))) {
508 printf("Already receiving in network ascii mode.\r\n");
509 } else {
510 printf("Negotiating network ascii mode on input.\r\n");
511 tel_leave_binary(1);
512 }
513 }
514 return 1;
515}
516
517static int
518togxbinary(int val)
519{
520 donebinarytoggle = 1;
521
522 if (val == -1)
523 val = my_want_state_is_will(TELOPT_BINARY)(options[0]&0x02) ? 0 : 1;
524
525 if (val == 1) {
526 if (my_want_state_is_will(TELOPT_BINARY)(options[0]&0x02)) {
527 printf("Already transmitting in binary mode.\r\n");
528 } else {
529 printf("Negotiating binary mode on output.\r\n");
530 tel_enter_binary(2);
531 }
532 } else {
533 if (my_want_state_is_wont(TELOPT_BINARY)(!(options[0]&0x02))) {
534 printf("Already transmitting in network ascii mode.\r\n");
535 } else {
536 printf("Negotiating network ascii mode on output.\r\n");
537 tel_leave_binary(2);
538 }
539 }
540 return 1;
541}
542
543
544static int togglehelp(int);
545
546struct togglelist {
547 char *name; /* name of toggle */
548 char *help; /* help message */
549 int (*handler)(int); /* routine to do actual setting */
550 int *variable;
551 char *actionexplanation;
552 int needconnect; /* Need to be connected */
553};
554
555static struct togglelist Togglelist[] = {
556 { "autoflush",
557 "flushing of output when sending interrupt characters",
558 0,
559 &autoflush,
560 "flush output when sending interrupt characters" },
561 { "autosynch",
562 "automatic sending of interrupt characters in urgent mode",
563 0,
564 &autosynch,
565 "send interrupt characters in urgent mode" },
566 { "autologin",
567 "automatic sending of login name",
568 0,
569 &autologin,
570 "send login name" },
571 { "skiprc",
572 "don't read ~/.telnetrc file",
573 0,
574 &skiprc,
575 "skip reading of ~/.telnetrc file" },
576 { "binary",
577 "sending and receiving of binary data",
578 togbinary,
579 0,
580 0 },
581 { "inbinary",
582 "receiving of binary data",
583 togrbinary,
584 0,
585 0 },
586 { "outbinary",
587 "sending of binary data",
588 togxbinary,
589 0,
590 0 },
591 { "crlf",
592 "sending carriage returns as telnet <CR><LF>",
593 togcrlf,
594 &crlf,
595 0 },
596 { "crmod",
597 "mapping of received carriage returns",
598 0,
599 &crmod,
600 "map carriage return on output" },
601 { "localchars",
602 "local recognition of certain control characters",
603 lclchars,
604 &localchars,
605 "recognize certain control characters" },
606 { " ", "", 0, 0 }, /* empty line */
607 { "netdata",
608 "printing of hexadecimal network data (debugging)",
609 0,
610 &netdata,
611 "print hexadecimal representation of network traffic" },
612 { "prettydump",
613 "output of \"netdata\" to user readable format (debugging)",
614 0,
615 &prettydump,
616 "print user readable output for \"netdata\"" },
617 { "options",
618 "viewing of options processing (debugging)",
619 0,
620 &showoptions,
621 "show option processing" },
622 { "termdata",
623 "(debugging) toggle printing of hexadecimal terminal data",
624 0,
625 &termdata,
626 "print hexadecimal representation of terminal traffic" },
627 { "?",
628 0,
629 togglehelp },
630 { "help",
631 0,
632 togglehelp },
633 { 0 }
634};
635
636static int
637togglehelp(int unused)
638{
639 struct togglelist *c;
640
641 for (c = Togglelist; c->name; c++) {
642 if (c->help) {
643 if (*c->help)
644 printf("%-15s toggle %s\r\n", c->name, c->help);
645 else
646 printf("\r\n");
647 }
648 }
649 printf("\r\n");
650 printf("%-15s %s\r\n", "?", "display help information");
651 return 0;
652}
653
654static void
655settogglehelp(int set)
656{
657 struct togglelist *c;
658
659 for (c = Togglelist; c->name; c++) {
660 if (c->help) {
661 if (*c->help)
662 printf("%-15s %s %s\r\n", c->name, set ? "enable" : "disable",
663 c->help);
664 else
665 printf("\r\n");
666 }
667 }
668}
669
670#define GETTOGGLE(name)(struct togglelist *) genget(name, (char **) Togglelist, sizeof
(struct togglelist))
(struct togglelist *) \
671 genget(name, (char **) Togglelist, sizeof(struct togglelist))
672
673static int
674toggle(int argc, char *argv[])
675{
676 int retval = 1;
677 char *name;
678 struct togglelist *c;
679
680 if (argc < 2) {
681 fprintf(stderr(&__sF[2]),
682 "Need an argument to 'toggle' command. 'toggle ?' for help.\r\n");
683 return 0;
684 }
685 argc--;
686 argv++;
687 while (argc--) {
688 name = *argv++;
689 c = GETTOGGLE(name)(struct togglelist *) genget(name, (char **) Togglelist, sizeof
(struct togglelist))
;
690 if (Ambiguous(c)) {
691 fprintf(stderr(&__sF[2]), "'%s': ambiguous argument ('toggle ?' for help).\r\n",
692 name);
693 return 0;
694 } else if (c == 0) {
695 fprintf(stderr(&__sF[2]), "'%s': unknown argument ('toggle ?' for help).\r\n",
696 name);
697 return 0;
698 } else if (!connected && c->needconnect) {
699 printf("?Need to be connected first.\r\n");
700 printf("'send ?' for help\r\n");
701 return 0;
702 } else {
703 if (c->variable) {
704 *c->variable = !*c->variable; /* invert it */
705 if (c->actionexplanation) {
706 printf("%s %s.\r\n", *c->variable? "Will" : "Won't",
707 c->actionexplanation);
708 }
709 }
710 if (c->handler) {
711 retval &= (*c->handler)(-1);
712 }
713 }
714 }
715 return retval;
716}
717
718/*
719 * The following perform the "set" command.
720 */
721
722struct termios new_tc = { 0 };
723
724struct setlist {
725 char *name; /* name */
726 char *help; /* help information */
727 void (*handler)(const char *);
728 cc_t *charp; /* where it is located at */
729};
730
731static struct setlist Setlist[] = {
732#ifdef KLUDGELINEMODE1
733 { "echo", "character to toggle local echoing on/off", 0, &echoc },
734#endif
735 { "escape", "character to escape back to telnet command mode", 0, &escape },
736 { "rlogin", "rlogin escape character", 0, &rlogin },
737 { " ", "" },
738 { " ", "The following need 'localchars' to be toggled true", 0, 0 },
739 { "flushoutput", "character to cause an Abort Output", 0, &termFlushCharnew_tc.c_cc[15] },
740 { "interrupt", "character to cause an Interrupt Process", 0, &termIntCharnew_tc.c_cc[8] },
741 { "quit", "character to cause an Abort process", 0, &termQuitCharnew_tc.c_cc[9] },
742 { "eof", "character to cause an EOF ", 0, &termEofCharnew_tc.c_cc[0] },
743 { " ", "" },
744 { " ", "The following are for local editing in linemode", 0, 0 },
745 { "erase", "character to use to erase a character", 0, &termEraseCharnew_tc.c_cc[3] },
746 { "kill", "character to use to erase a line", 0, &termKillCharnew_tc.c_cc[5] },
747 { "lnext", "character to use for literal next", 0, &termLiteralNextCharnew_tc.c_cc[14] },
748 { "susp", "character to cause a Suspend Process", 0, &termSuspCharnew_tc.c_cc[10] },
749 { "reprint", "character to use for line reprint", 0, &termRprntCharnew_tc.c_cc[6] },
750 { "worderase", "character to use to erase a word", 0, &termWerasCharnew_tc.c_cc[4] },
751 { "start", "character to use for XON", 0, &termStartCharnew_tc.c_cc[12] },
752 { "stop", "character to use for XOFF", 0, &termStopCharnew_tc.c_cc[13] },
753 { "forw1", "alternate end of line character", 0, &termForw1Charnew_tc.c_cc[1] },
754 { "forw2", "alternate end of line character", 0, &termForw2Charnew_tc.c_cc[1] },
755 { "ayt", "alternate AYT character", 0, &termAytCharnew_tc.c_cc[18] },
756 { 0 }
757};
758
759static struct setlist *
760getset(char *name)
761{
762 return (struct setlist *)
763 genget(name, (char **) Setlist, sizeof(struct setlist));
764}
765
766void
767set_escape_char(char *s)
768{
769 if (rlogin != _POSIX_VDISABLE(0377)) {
770 rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE(0377);
771 printf("Telnet rlogin escape character is '%s'.\r\n",
772 control(rlogin));
773 } else {
774 escape = (s && *s) ? special(s) : _POSIX_VDISABLE(0377);
775 printf("Telnet escape character is '%s'.\r\n", control(escape));
776 }
777}
778
779static int
780setcmd(int argc, char *argv[])
781{
782 int value;
783 struct setlist *ct;
784 struct togglelist *c;
785
786 if (argc < 2 || argc > 3) {
787 printf("Format is 'set Name Value'\r\n'set ?' for help.\r\n");
788 return 0;
789 }
790 if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
791 for (ct = Setlist; ct->name; ct++)
792 printf("%-15s %s\r\n", ct->name, ct->help);
793 printf("\r\n");
794 settogglehelp(1);
795 printf("%-15s %s\r\n", "?", "display help information");
796 return 0;
797 }
798
799 ct = getset(argv[1]);
800 if (ct == 0) {
801 c = GETTOGGLE(argv[1])(struct togglelist *) genget(argv[1], (char **) Togglelist, sizeof
(struct togglelist))
;
802 if (c == 0) {
803 fprintf(stderr(&__sF[2]), "'%s': unknown argument ('set ?' for help).\r\n",
804 argv[1]);
805 return 0;
806 } else if (Ambiguous(c)) {
807 fprintf(stderr(&__sF[2]), "'%s': ambiguous argument ('set ?' for help).\r\n",
808 argv[1]);
809 return 0;
810 } else if (!connected && c->needconnect) {
811 printf("?Need to be connected first.\r\n");
812 printf("'send ?' for help\r\n");
813 return 0;
814 }
815
816 if (c->variable) {
817 if ((argc == 2) || (strcmp("on", argv[2]) == 0))
818 *c->variable = 1;
819 else if (strcmp("off", argv[2]) == 0)
820 *c->variable = 0;
821 else {
822 printf("Format is 'set togglename [on|off]'\r\n'set ?' for help.\r\n");
823 return 0;
824 }
825 if (c->actionexplanation) {
826 printf("%s %s.\r\n", *c->variable? "Will" : "Won't",
827 c->actionexplanation);
828 }
829 }
830 if (c->handler)
831 (*c->handler)(1);
832 } else if (argc != 3) {
833 printf("Format is 'set Name Value'\r\n'set ?' for help.\r\n");
834 return 0;
835 } else if (Ambiguous(ct)) {
836 fprintf(stderr(&__sF[2]), "'%s': ambiguous argument ('set ?' for help).\r\n",
837 argv[1]);
838 return 0;
839 } else if (ct->handler) {
840 (*ct->handler)(argv[2]);
841 printf("%s set to \"%s\".\r\n", ct->name, (char *)ct->charp);
842 } else {
843 if (strcmp("off", argv[2])) {
844 value = special(argv[2]);
845 } else {
846 value = _POSIX_VDISABLE(0377);
847 }
848 *(ct->charp) = (cc_t)value;
849 printf("%s character is '%s'.\r\n", ct->name, control(*(ct->charp)));
850 }
851 slc_check();
852 return 1;
853}
854
855static int
856unsetcmd(int argc, char *argv[])
857{
858 struct setlist *ct;
859 struct togglelist *c;
860 char *name;
861
862 if (argc < 2) {
863 fprintf(stderr(&__sF[2]),
864 "Need an argument to 'unset' command. 'unset ?' for help.\r\n");
865 return 0;
866 }
867 if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
868 for (ct = Setlist; ct->name; ct++)
869 printf("%-15s %s\r\n", ct->name, ct->help);
870 printf("\r\n");
871 settogglehelp(0);
872 printf("%-15s %s\r\n", "?", "display help information");
873 return 0;
874 }
875
876 argc--;
877 argv++;
878 while (argc--) {
879 name = *argv++;
880 ct = getset(name);
881 if (ct == 0) {
882 c = GETTOGGLE(name)(struct togglelist *) genget(name, (char **) Togglelist, sizeof
(struct togglelist))
;
883 if (c == 0) {
884 fprintf(stderr(&__sF[2]), "'%s': unknown argument ('unset ?' for help).\r\n",
885 name);
886 return 0;
887 } else if (Ambiguous(c)) {
888 fprintf(stderr(&__sF[2]), "'%s': ambiguous argument ('unset ?' for help).\r\n",
889 name);
890 return 0;
891 }
892 if (c->variable) {
893 *c->variable = 0;
894 if (c->actionexplanation) {
895 printf("%s %s.\r\n", *c->variable? "Will" : "Won't",
896 c->actionexplanation);
897 }
898 }
899 if (c->handler)
900 (*c->handler)(0);
901 } else if (Ambiguous(ct)) {
902 fprintf(stderr(&__sF[2]), "'%s': ambiguous argument ('unset ?' for help).\r\n",
903 name);
904 return 0;
905 } else if (ct->handler) {
906 (*ct->handler)(NULL((void *)0));
907 printf("%s reset to \"%s\".\r\n", ct->name, (char *)ct->charp);
908 } else {
909 *(ct->charp) = _POSIX_VDISABLE(0377);
910 printf("%s character is '%s'.\r\n", ct->name, control(*(ct->charp)));
911 }
912 }
913 return 1;
914}
915
916/*
917 * The following are the data structures and routines for the
918 * 'mode' command.
919 */
920#ifdef KLUDGELINEMODE1
921static int
922dokludgemode(int unused)
923{
924 kludgelinemode = 1;
925 send_wont(TELOPT_LINEMODE34, 1);
926 send_dont(TELOPT_SGA3, 1);
927 send_dont(TELOPT_ECHO1, 1);
928 return 1;
929}
930#endif
931
932static int
933dolinemode(int unused)
934{
935#ifdef KLUDGELINEMODE1
936 if (kludgelinemode)
937 send_dont(TELOPT_SGA3, 1);
938#endif
939 send_will(TELOPT_LINEMODE34, 1);
940 send_dont(TELOPT_ECHO1, 1);
941 return 1;
942}
943
944static int
945docharmode(int unused)
946{
947#ifdef KLUDGELINEMODE1
948 if (kludgelinemode)
949 send_do(TELOPT_SGA3, 1);
950 else
951#endif
952 send_wont(TELOPT_LINEMODE34, 1);
953 send_do(TELOPT_ECHO1, 1);
954 return 1;
955}
956
957static int
958dolmmode(int bit, int on)
959{
960 unsigned char c;
961
962 if (my_want_state_is_wont(TELOPT_LINEMODE)(!(options[34]&0x02))) {
963 printf("?Need to have LINEMODE option enabled first.\r\n");
964 printf("'mode ?' for help.\r\n");
965 return 0;
966 }
967
968 if (on)
969 c = (linemode | bit);
970 else
971 c = (linemode & ~bit);
972 lm_mode(&c, 1, 1);
973 return 1;
974}
975
976int
977tn_setmode(int bit)
978{
979 return dolmmode(bit, 1);
980}
981
982int
983tn_clearmode(int bit)
984{
985 return dolmmode(bit, 0);
986}
987
988struct modelist {
989 char *name; /* command name */
990 char *help; /* help string */
991 int (*handler)(int);/* routine which executes command */
992 int needconnect; /* Do we need to be connected to execute? */
993 int arg1;
994};
995
996static int modehelp(int);
997
998static struct modelist ModeList[] = {
999 { "character", "Disable LINEMODE option", docharmode, 1 },
1000#ifdef KLUDGELINEMODE1
1001 { "", "(or disable obsolete line-by-line mode)", 0 },
1002#endif
1003 { "line", "Enable LINEMODE option", dolinemode, 1 },
1004#ifdef KLUDGELINEMODE1
1005 { "", "(or enable obsolete line-by-line mode)", 0 },
1006#endif
1007 { "", "", 0 },
1008 { "", "These require the LINEMODE option to be enabled", 0 },
1009 { "isig", "Enable signal trapping", tn_setmode, 1, MODE_TRAPSIG0x02 },
1010 { "+isig", 0, tn_setmode, 1, MODE_TRAPSIG0x02 },
1011 { "-isig", "Disable signal trapping", tn_clearmode, 1, MODE_TRAPSIG0x02 },
1012 { "edit", "Enable character editing", tn_setmode, 1, MODE_EDIT0x01 },
1013 { "+edit", 0, tn_setmode, 1, MODE_EDIT0x01 },
1014 { "-edit", "Disable character editing", tn_clearmode, 1, MODE_EDIT0x01 },
1015 { "softtabs", "Enable tab expansion", tn_setmode, 1, MODE_SOFT_TAB0x08 },
1016 { "+softtabs", 0, tn_setmode, 1, MODE_SOFT_TAB0x08 },
1017 { "-softtabs", "Disable character editing", tn_clearmode, 1, MODE_SOFT_TAB0x08 },
1018 { "litecho", "Enable literal character echo", tn_setmode, 1, MODE_LIT_ECHO0x10 },
1019 { "+litecho", 0, tn_setmode, 1, MODE_LIT_ECHO0x10 },
1020 { "-litecho", "Disable literal character echo", tn_clearmode, 1, MODE_LIT_ECHO0x10 },
1021 { "help", 0, modehelp, 0 },
1022#ifdef KLUDGELINEMODE1
1023 { "kludgeline", 0, dokludgemode, 1 },
1024#endif
1025 { "", "", 0 },
1026 { "?", "Print help information", modehelp, 0 },
1027 { 0 },
1028};
1029
1030static int
1031modehelp(int unused)
1032{
1033 struct modelist *mt;
1034
1035 printf("format is: 'mode Mode', where 'Mode' is one of:\r\n\r\n");
1036 for (mt = ModeList; mt->name; mt++) {
1037 if (mt->help) {
1038 if (*mt->help)
1039 printf("%-15s %s\r\n", mt->name, mt->help);
1040 else
1041 printf("\r\n");
1042 }
1043 }
1044 return 0;
1045}
1046
1047#define GETMODECMD(name)(struct modelist *) genget(name, (char **) ModeList, sizeof(struct
modelist))
(struct modelist *) \
1048 genget(name, (char **) ModeList, sizeof(struct modelist))
1049
1050static int
1051modecmd(int argc, char *argv[])
1052{
1053 struct modelist *mt;
1054
1055 if (argc != 2) {
1056 printf("'mode' command requires an argument\r\n");
1057 printf("'mode ?' for help.\r\n");
1058 } else if ((mt = GETMODECMD(argv[1])(struct modelist *) genget(argv[1], (char **) ModeList, sizeof
(struct modelist))
) == 0) {
1059 fprintf(stderr(&__sF[2]), "Unknown mode '%s' ('mode ?' for help).\r\n", argv[1]);
1060 } else if (Ambiguous(mt)) {
1061 fprintf(stderr(&__sF[2]), "Ambiguous mode '%s' ('mode ?' for help).\r\n", argv[1]);
1062 } else if (mt->needconnect && !connected) {
1063 printf("?Need to be connected first.\r\n");
1064 printf("'mode ?' for help.\r\n");
1065 } else if (mt->handler) {
1066 return (*mt->handler)(mt->arg1);
1067 }
1068 return 0;
1069}
1070
1071/*
1072 * The following data structures and routines implement the
1073 * "display" command.
1074 */
1075
1076static int
1077display(int argc, char *argv[])
1078{
1079 struct togglelist *tl;
1080 struct setlist *sl;
1081
1082#define dotog(tl) if (tl->variable && tl->actionexplanation) { \
1083 if (*tl->variable) { \
1084 printf("will"); \
1085 } else { \
1086 printf("won't"); \
1087 } \
1088 printf(" %s.\r\n", tl->actionexplanation); \
1089 }
1090
1091#define doset(sl) if (sl->name && *sl->name != ' ') { \
1092 if (sl->handler == 0) \
1093 printf("%-15s [%s]\r\n", sl->name, control(*sl->charp)); \
1094 else \
1095 printf("%-15s \"%s\"\r\n", sl->name, (char *)sl->charp); \
1096 }
1097
1098 if (argc == 1) {
1099 for (tl = Togglelist; tl->name; tl++) {
1100 dotog(tl);
1101 }
1102 printf("\r\n");
1103 for (sl = Setlist; sl->name; sl++) {
1104 doset(sl);
1105 }
1106 } else {
1107 int i;
1108
1109 for (i = 1; i < argc; i++) {
1110 sl = getset(argv[i]);
1111 tl = GETTOGGLE(argv[i])(struct togglelist *) genget(argv[i], (char **) Togglelist, sizeof
(struct togglelist))
;
1112 if (Ambiguous(sl) || Ambiguous(tl)) {
1113 printf("?Ambiguous argument '%s'.\r\n", argv[i]);
1114 return 0;
1115 } else if (!sl && !tl) {
1116 printf("?Unknown argument '%s'.\r\n", argv[i]);
1117 return 0;
1118 } else {
1119 if (tl) {
1120 dotog(tl);
1121 }
1122 if (sl) {
1123 doset(sl);
1124 }
1125 }
1126 }
1127 }
1128/*@*/optionstatus();
1129 return 1;
1130#undef doset
1131#undef dotog
1132}
1133
1134/*
1135 * The following are the data structures, and many of the routines,
1136 * relating to command processing.
1137 */
1138
1139/*
1140 * Set the escape character.
1141 */
1142static int
1143setescape(int argc, char *argv[])
1144{
1145 char *arg;
1146 char buf[50];
1147
1148 printf(
1149 "Deprecated usage - please use 'set escape%s%s' in the future.\r\n",
1150 (argc > 2)? " ":"", (argc > 2)? argv[1]: "");
1151 if (argc > 2)
1152 arg = argv[1];
1153 else {
1154 printf("new escape character: ");
1155 (void) fgets(buf, sizeof(buf), stdin(&__sF[0]));
1156 arg = buf;
1157 }
1158 if (arg[0] != '\0')
1159 escape = arg[0];
1160 printf("Escape character is '%s'.\r\n", control(escape));
1161 (void) fflush(stdout(&__sF[1]));
1162 return 1;
1163}
1164
1165static int
1166togcrmod(int unused1, char *unused2[])
1167{
1168 crmod = !crmod;
1169 printf("Deprecated usage - please use 'toggle crmod' in the future.\r\n");
1170 printf("%s map carriage return on output.\r\n", crmod ? "Will" : "Won't");
1171 (void) fflush(stdout(&__sF[1]));
1172 return 1;
1173}
1174
1175int
1176telnetsuspend(int unused1, char *unused2[])
1177{
1178 setcommandmode();
1179 {
1180 long oldrows, oldcols, newrows, newcols, err;
1181
1182 err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
1183 (void) kill(0, SIGTSTP18);
1184 /*
1185 * If we didn't get the window size before the SUSPEND, but we
1186 * can get them now (?), then send the NAWS to make sure that
1187 * we are set up for the right window size.
1188 */
1189 if (TerminalWindowSize(&newrows, &newcols) && connected &&
1190 (err || ((oldrows != newrows) || (oldcols != newcols)))) {
1191 sendnaws();
1192 }
1193 }
1194 /* reget parameters in case they were changed */
1195 TerminalSaveState();
1196 setconnmode(0);
1197 return 1;
1198}
1199
1200static void
1201close_connection(void)
1202{
1203 if (connected) {
1204 (void) shutdown(net, SHUT_RDWR2);
1205 printf("Connection closed.\r\n");
1206 (void)close(net);
1207 connected = 0;
1208 resettermname = 1;
1209 /* reset options */
1210 tninit();
1211 }
1212}
1213
1214static int
1215bye(int argc, char *argv[])
1216{
1217 close_connection();
1218 longjmp(toplevel, 1);
1219}
1220
1221void
1222quit(void)
1223{
1224 close_connection();
1225 Exit(0);
1226}
1227
1228static int
1229quitcmd(int unused1, char *unused2[])
1230{
1231 quit();
1232}
1233
1234static int
1235logout(int unused1, char *unused2[])
1236{
1237 send_do(TELOPT_LOGOUT18, 1);
1238 (void) netflush();
1239 return 1;
1240}
1241
1242
1243/*
1244 * The SLC command.
1245 */
1246
1247struct slclist {
1248 char *name;
1249 char *help;
1250 void (*handler)(int);
1251 int arg;
1252};
1253
1254static void slc_help(int);
1255
1256struct slclist SlcList[] = {
1257 { "export", "Use local special character definitions",
1258 slc_mode_export, 0 },
1259 { "import", "Use remote special character definitions",
1260 slc_mode_import, 1 },
1261 { "check", "Verify remote special character definitions",
1262 slc_mode_import, 0 },
1263 { "help", 0, slc_help, 0 },
1264 { "?", "Print help information", slc_help, 0 },
1265 { 0 },
1266};
1267
1268static void
1269slc_help(int unused)
1270{
1271 struct slclist *c;
1272
1273 for (c = SlcList; c->name; c++) {
1274 if (c->help) {
1275 if (*c->help)
1276 printf("%-15s %s\r\n", c->name, c->help);
1277 else
1278 printf("\r\n");
1279 }
1280 }
1281}
1282
1283static struct slclist *
1284getslc(char *name)
1285{
1286 return (struct slclist *)
1287 genget(name, (char **) SlcList, sizeof(struct slclist));
1288}
1289
1290static int
1291slccmd(int argc, char *argv[])
1292{
1293 struct slclist *c;
1294
1295 if (argc != 2) {
1296 fprintf(stderr(&__sF[2]),
1297 "Need an argument to 'slc' command. 'slc ?' for help.\r\n");
1298 return 0;
1299 }
1300 c = getslc(argv[1]);
1301 if (c == 0) {
1302 fprintf(stderr(&__sF[2]), "'%s': unknown argument ('slc ?' for help).\r\n",
1303 argv[1]);
1304 return 0;
1305 }
1306 if (Ambiguous(c)) {
1307 fprintf(stderr(&__sF[2]), "'%s': ambiguous argument ('slc ?' for help).\r\n",
1308 argv[1]);
1309 return 0;
1310 }
1311 (*c->handler)(c->arg);
1312 slcstate();
1313 return 1;
1314}
1315
1316/*
1317 * The ENVIRON command.
1318 */
1319
1320struct envlist {
1321 char *name;
1322 char *help;
1323 void (*handler)();
1324 int narg;
1325};
1326
1327static void env_help(void);
1328static void env_undefine(const char *);
1329static void env_export(const char *);
1330static void env_unexport(const char *);
1331static void env_send(const char *);
1332static void env_list(void);
1333static struct env_lst *env_find(const char *var);
1334
1335struct envlist EnvList[] = {
1336 { "define", "Define an environment variable",
1337 (void (*)())env_define, 2 },
1338 { "undefine", "Undefine an environment variable",
1339 env_undefine, 1 },
1340 { "export", "Mark an environment variable for automatic export",
1341 env_export, 1 },
1342 { "unexport", "Don't mark an environment variable for automatic export",
1343 env_unexport, 1 },
1344 { "send", "Send an environment variable", env_send, 1 },
1345 { "list", "List the current environment variables",
1346 env_list, 0 },
1347 { "help", 0, env_help, 0 },
1348 { "?", "Print help information", env_help, 0 },
1349 { 0 },
1350};
1351
1352static void
1353env_help(void)
1354{
1355 struct envlist *c;
1356
1357 for (c = EnvList; c->name; c++) {
1358 if (c->help) {
1359 if (*c->help)
1360 printf("%-15s %s\r\n", c->name, c->help);
1361 else
1362 printf("\r\n");
1363 }
1364 }
1365}
1366
1367static struct envlist *
1368getenvcmd(char *name)
1369{
1370 return (struct envlist *)
1371 genget(name, (char **) EnvList, sizeof(struct envlist));
1372}
1373
1374static int
1375env_cmd(int argc, char *argv[])
1376{
1377 struct envlist *c;
1378
1379 if (argc < 2) {
1380 fprintf(stderr(&__sF[2]),
1381 "Need an argument to 'environ' command. 'environ ?' for help.\r\n");
1382 return 0;
1383 }
1384 c = getenvcmd(argv[1]);
1385 if (c == 0) {
1386 fprintf(stderr(&__sF[2]), "'%s': unknown argument ('environ ?' for help).\r\n",
1387 argv[1]);
1388 return 0;
1389 }
1390 if (Ambiguous(c)) {
1391 fprintf(stderr(&__sF[2]), "'%s': ambiguous argument ('environ ?' for help).\r\n",
1392 argv[1]);
1393 return 0;
1394 }
1395 if (c->narg + 2 != argc) {
1396 fprintf(stderr(&__sF[2]),
1397 "Need %s%d argument%s to 'environ %s' command. 'environ ?' for help.\r\n",
1398 c->narg < argc + 2 ? "only " : "",
1399 c->narg, c->narg == 1 ? "" : "s", c->name);
1400 return 0;
1401 }
1402 (*c->handler)(argv[2], argv[3]);
1403 return 1;
1404}
1405
1406struct env_lst {
1407 struct env_lst *next; /* pointer to next structure */
1408 struct env_lst *prev; /* pointer to previous structure */
1409 char *var; /* pointer to variable name */
1410 char *value; /* pointer to variable value */
1411 int export; /* 1 -> export with default list of variables */
1412 int welldefined; /* A well defined variable */
1413};
1414
1415struct env_lst envlisthead;
1416
1417static struct env_lst *
1418env_find(const char *var)
1419{
1420 struct env_lst *ep;
1421
1422 for (ep = envlisthead.next; ep; ep = ep->next) {
1423 if (strcmp(ep->var, var) == 0)
1424 return(ep);
1425 }
1426 return(NULL((void *)0));
1427}
1428
1429void
1430env_init(void)
1431{
1432 extern char **environ;
1433 char **epp, *cp;
1434 struct env_lst *ep;
1435
1436 for (epp = environ; *epp; epp++) {
1437 if ((cp = strchr(*epp, '='))) {
1438 *cp = '\0';
1439 ep = env_define(*epp, cp+1);
1440 ep->export = 0;
1441 *cp = '=';
1442 }
1443 }
1444 /*
1445 * Special case for DISPLAY variable. If it is ":0.0" or
1446 * "unix:0.0", we have to get rid of "unix" and insert our
1447 * hostname.
1448 */
1449 if ((ep = env_find("DISPLAY"))
1450 && ((*ep->value == ':')
1451 || (strncmp(ep->value, "unix:", 5) == 0))) {
1452 char hbuf[HOST_NAME_MAX255+1];
1453 char *cp2 = strchr(ep->value, ':');
1454
1455 gethostname(hbuf, sizeof hbuf);
1456
1457 if (asprintf (&cp, "%s%s", hbuf, cp2) == -1)
1458 err(1, "asprintf");
1459
1460 free(ep->value);
1461 ep->value = cp;
1462 }
1463 /*
1464 * If USER is not defined, but LOGNAME is, then add
1465 * USER with the value from LOGNAME. By default, we
1466 * don't export the USER variable.
1467 */
1468 if ((env_find("USER") == NULL((void *)0)) && (ep = env_find("LOGNAME"))) {
1469 env_define("USER", ep->value);
1470 env_unexport("USER");
1471 }
1472 env_export("DISPLAY");
1473 env_export("PRINTER");
1474 env_export("XAUTHORITY");
1475}
1476
1477struct env_lst *
1478env_define(const char *var, const char *value)
1479{
1480 struct env_lst *ep;
1481
1482 if ((ep = env_find(var))) {
1483 free(ep->var);
1484 free(ep->value);
1485 } else {
1486 if ((ep = malloc(sizeof(struct env_lst))) == NULL((void *)0))
1487 err(1, "malloc");
1488 ep->next = envlisthead.next;
1489 envlisthead.next = ep;
1490 ep->prev = &envlisthead;
1491 if (ep->next)
1492 ep->next->prev = ep;
1493 }
1494 ep->welldefined = opt_welldefined(var);
1495 ep->export = 1;
1496 if ((ep->var = strdup(var)) == NULL((void *)0))
1497 err(1, "strdup");
1498 if ((ep->value = strdup(value)) == NULL((void *)0))
1499 err(1, "strdup");
1500 return(ep);
1501}
1502
1503static void
1504env_undefine(const char *var)
1505{
1506 struct env_lst *ep;
1507
1508 if ((ep = env_find(var))) {
1509 ep->prev->next = ep->next;
1510 if (ep->next)
1511 ep->next->prev = ep->prev;
1512 free(ep->var);
1513 free(ep->value);
1514 free(ep);
1515 }
1516}
1517
1518static void
1519env_export(const char *var)
1520{
1521 struct env_lst *ep;
1522
1523 if ((ep = env_find(var)))
1524 ep->export = 1;
1525}
1526
1527static void
1528env_unexport(const char *var)
1529{
1530 struct env_lst *ep;
1531
1532 if ((ep = env_find(var)) != NULL((void *)0))
1533 ep->export = 0;
1534}
1535
1536static void
1537env_send(const char *var)
1538{
1539 struct env_lst *ep;
1540
1541 if (my_state_is_wont(TELOPT_NEW_ENVIRON)(!(options[39]&0x01))
1542 ) {
1543 fprintf(stderr(&__sF[2]),
1544 "Cannot send '%s': Telnet ENVIRON option not enabled\r\n",
1545 var);
1546 return;
1547 }
1548 ep = env_find(var);
1549 if (ep == 0) {
1550 fprintf(stderr(&__sF[2]), "Cannot send '%s': variable not defined\r\n",
1551 var);
1552 return;
1553 }
1554 env_opt_start_info();
1555 env_opt_add(ep->var);
1556 env_opt_end(0);
1557}
1558
1559static void
1560env_list(void)
1561{
1562 struct env_lst *ep;
1563
1564 for (ep = envlisthead.next; ep; ep = ep->next) {
1565 printf("%c %-20s %s\r\n", ep->export ? '*' : ' ',
1566 ep->var, ep->value);
1567 }
1568}
1569
1570char *
1571env_default(int init, int welldefined)
1572{
1573 static struct env_lst *nep = NULL((void *)0);
1574
1575 if (init) {
1576 nep = &envlisthead;
1577 return NULL((void *)0);
1578 }
1579 if (nep) {
1580 while ((nep = nep->next)) {
1581 if (nep->export && (nep->welldefined == welldefined))
1582 return(nep->var);
1583 }
1584 }
1585 return(NULL((void *)0));
1586}
1587
1588char *
1589env_getvalue(const char *var, int exported_only)
1590{
1591 struct env_lst *ep;
1592
1593 if ((ep = env_find(var)) && (!exported_only || ep->export))
1594 return(ep->value);
1595 return(NULL((void *)0));
1596}
1597
1598static void
1599connection_status(int local_only)
1600{
1601 if (!connected)
1602 printf("No connection.\r\n");
1603 else {
1604 printf("Connected to %s.\r\n", hostname);
1605 if (!local_only) {
1606 int mode = getconnmode();
1607
1608 printf("Operating ");
1609 if (my_want_state_is_will(TELOPT_LINEMODE)(options[34]&0x02)) {
1610 printf("with LINEMODE option\r\n"
1611 "%s line editing\r\n"
1612 "%s catching of signals\r\n",
1613 (mode & MODE_EDIT0x01) ? "Local" : "No",
1614 (mode & MODE_TRAPSIG0x02) ? "Local" : "No");
1615 slcstate();
1616#ifdef KLUDGELINEMODE1
1617 } else if (kludgelinemode &&
1618 my_want_state_is_dont(TELOPT_SGA)(!(options[3]&0x08))) {
1619 printf("in obsolete linemode\r\n");
1620#endif
1621 } else {
1622 printf("in single character mode\r\n");
1623 if (localchars)
1624 printf("Catching signals locally\r\n");
1625 }
1626
1627 printf("%s character echo\r\n",
1628 (mode & MODE_ECHO0x0200) ? "Local" : "Remote");
1629 if (my_want_state_is_will(TELOPT_LFLOW)(options[33]&0x02))
1630 printf("%s flow control\r\n",
1631 (mode & MODE_FLOW0x0100) ? "Local" : "No");
1632 }
1633 }
1634 printf("Escape character is '%s'.\r\n", control(escape));
1635 (void) fflush(stdout(&__sF[1]));
1636}
1637
1638/*
1639 * Print status about the connection.
1640 */
1641static int
1642status(int argc, char *argv[])
1643{
1644 connection_status(0);
1645 return 1;
1646}
1647
1648/*
1649 * Function that gets called when SIGINFO is received.
1650 */
1651void
1652ayt_status(int sig)
1653{
1654 connection_status(1);
1655}
1656
1657static Command *getcmd(char *name);
1658
1659static void
1660cmdrc(char *m1, char *m2)
1661{
1662 static char rcname[128];
1663 Command *c;
1664 FILE *rcfile;
1665 int gotmachine = 0;
1666 int l1 = strlen(m1);
1667 int l2 = strlen(m2);
1668 char m1save[HOST_NAME_MAX255+1];
1669
1670 if (skiprc)
1671 return;
1672
1673 strlcpy(m1save, m1, sizeof(m1save));
1674 m1 = m1save;
1675
1676 if (rcname[0] == 0) {
1677 char *home = getenv("HOME");
1678
1679 if (home == NULL((void *)0) || *home == '\0')
1680 return;
1681 snprintf (rcname, sizeof(rcname), "%s/.telnetrc",
1682 home ? home : "");
1683 }
1684
1685 if ((rcfile = fopen(rcname, "r")) == 0) {
1686 return;
1687 }
1688
1689 for (;;) {
1690 if (fgets(line, sizeof(line), rcfile) == NULL((void *)0))
1691 break;
1692 if (line[0] == 0)
1693 break;
1694 if (line[0] == '#')
1695 continue;
1696 if (gotmachine) {
1697 if (!isspace((unsigned char)line[0]))
1698 gotmachine = 0;
1699 }
1700 if (gotmachine == 0) {
1701 if (isspace((unsigned char)line[0]))
1702 continue;
1703 if (strncasecmp(line, m1, l1) == 0)
1704 strncpy(line, &line[l1], sizeof(line) - l1);
1705 else if (strncasecmp(line, m2, l2) == 0)
1706 strncpy(line, &line[l2], sizeof(line) - l2);
1707 else if (strncasecmp(line, "DEFAULT", 7) == 0)
1708 strncpy(line, &line[7], sizeof(line) - 7);
1709 else
1710 continue;
1711 if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
1712 continue;
1713 gotmachine = 1;
1714 }
1715 if (makeargv())
1716 continue;
1717 if (margv[0] == 0)
1718 continue;
1719 c = getcmd(margv[0]);
1720 if (Ambiguous(c)) {
1721 printf("?Ambiguous command: %s\r\n", margv[0]);
1722 continue;
1723 }
1724 if (c == 0) {
1725 printf("?Invalid command: %s\r\n", margv[0]);
1726 continue;
1727 }
1728 /*
1729 * This should never happen...
1730 */
1731 if (c->needconnect && !connected) {
1732 printf("?Need to be connected first for %s.\r\n", margv[0]);
1733 continue;
1734 }
1735 (*c->handler)(margc, margv);
1736 }
1737 fclose(rcfile);
1738}
1739
1740int
1741tn(int argc, char *argv[])
1742{
1743 struct addrinfo hints, *res, *res0;
1744 char *cmd, *hostp = 0, *portp = 0, *user = 0, *aliasp = 0;
1745 int error, retry;
1746 const int niflags = NI_NUMERICHOST1, tos = IPTOS_LOWDELAY0x10;
1747
1748 if (connected) {
1
Assuming 'connected' is 0
2
Taking false branch
1749 printf("?Already connected to %s\r\n", hostname);
1750 return 0;
1751 }
1752 if (connections) {
3
Assuming 'connections' is 0
4
Taking false branch
1753 printf("Repeated connections not supported\r\n");
1754 return 0;
1755 }
1756 if (argc < 2) {
5
Assuming 'argc' is >= 2
6
Taking false branch
1757 strlcpy(line, "open ", sizeof(line));
1758 printf("(to) ");
1759 (void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin(&__sF[0]));
1760 if (makeargv())
1761 return 0;
1762 argc = margc;
1763 argv = margv;
1764 }
1765 cmd = *argv;
1766 --argc; ++argv;
1767 while (argc) {
7
Loop condition is true. Entering loop body
18
Loop condition is false. Execution continues on line 1806
1768 if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?"))
8
Assuming the condition is false
9
Assuming the condition is false
10
Taking false branch
1769 goto usage;
1770 if (strcmp(*argv, "-l") == 0) {
11
Taking true branch
1771 --argc; ++argv;
1772 if (argc == 0)
12
Assuming 'argc' is not equal to 0
13
Taking false branch
1773 goto usage;
1774 if ((user = strdup(*argv++)) == NULL((void *)0))
14
Memory is allocated
15
Assuming the condition is false
16
Taking false branch
1775 err(1, "strdup");
1776 --argc;
1777 continue;
17
Execution continues on line 1767
1778 }
1779 if (strcmp(*argv, "-b") == 0) {
1780 --argc; ++argv;
1781 if (argc == 0)
1782 goto usage;
1783 aliasp = *argv++;
1784 --argc;
1785 continue;
1786 }
1787 if (strcmp(*argv, "-a") == 0) {
1788 --argc; ++argv;
1789 autologin = 1;
1790 continue;
1791 }
1792 if (hostp == 0) {
1793 hostp = *argv++;
1794 --argc;
1795 continue;
1796 }
1797 if (portp == 0) {
1798 portp = *argv++;
1799 --argc;
1800 continue;
1801 }
1802 usage:
1803 printf("usage: %s [-a] [-b hostalias] [-l user] host-name [port]\r\n", cmd);
21
Potential leak of memory pointed to by 'user'
1804 return 0;
1805 }
1806 if (hostp
18.1
'hostp' is equal to null
== 0)
19
Taking true branch
1807 goto usage;
20
Control jumps to line 1803
1808
1809 hostname = hostp;
1810 memset(&hints, 0, sizeof(hints));
1811 hints.ai_family = family;
1812 hints.ai_socktype = SOCK_STREAM1;
1813 hints.ai_flags = AI_CANONNAME2;
1814 if (portp == NULL((void *)0)) {
1815 portp = "telnet";
1816 telnetport = 1;
1817 } else if (*portp == '-') {
1818 portp++;
1819 telnetport = 1;
1820 } else
1821 telnetport = 0;
1822 error = getaddrinfo(hostp, portp, &hints, &res0);
1823 if (error) {
1824 if (error == EAI_SERVICE-8)
1825 warnx("%s: bad port", portp);
1826 else
1827 warnx("%s: %s", hostp, gai_strerror(error));
1828 return 0;
1829 }
1830
1831 net = -1;
1832 retry = 0;
1833 for (res = res0; res; res = res->ai_next) {
1834 if (1 /* retry */) {
1835 char hbuf[NI_MAXHOST256];
1836
1837 if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
1838 NULL((void *)0), 0, niflags) != 0) {
1839 strlcpy(hbuf, "(invalid)", sizeof(hbuf));
1840 }
1841 printf("Trying %s...\r\n", hbuf);
1842 }
1843 net = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
1844 if (net == -1)
1845 continue;
1846
1847 if (aliasp) {
1848 struct addrinfo ahints, *ares;
1849
1850 memset(&ahints, 0, sizeof(ahints));
1851 ahints.ai_family = family;
1852 ahints.ai_socktype = SOCK_STREAM1;
1853 ahints.ai_flags = AI_PASSIVE1;
1854 error = getaddrinfo(aliasp, "0", &ahints, &ares);
1855 if (error) {
1856 warn("%s: %s", aliasp, gai_strerror(error));
1857 close(net);
1858 net = -1;
1859 continue;
1860 }
1861 if (bind(net, ares->ai_addr, ares->ai_addrlen) == -1) {
1862 perror(aliasp);
1863 (void) close(net); /* dump descriptor */
1864 net = -1;
1865 freeaddrinfo(ares);
1866 continue;
1867 }
1868 freeaddrinfo(ares);
1869 }
1870
1871 switch (res->ai_family) {
1872 case AF_INET2:
1873 if (setsockopt(net, IPPROTO_IP0, IP_TOS3, &tos, sizeof(tos)) == -1
1874 && errno(*__errno()) != ENOPROTOOPT42)
1875 perror("telnet: setsockopt (IP_TOS) (ignored)");
1876 break;
1877 case AF_INET624:
1878 if (setsockopt(net, IPPROTO_IPV641, IPV6_TCLASS61, &tos,
1879 sizeof(tos)) == -1 && errno(*__errno()) != ENOPROTOOPT42)
1880 perror("telnet: setsockopt (IPV6_TCLASS) (ignored)");
1881 break;
1882 }
1883
1884 if (connect(net, res->ai_addr, res->ai_addrlen) == -1) {
1885 char hbuf[NI_MAXHOST256];
1886
1887 if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
1888 NULL((void *)0), 0, niflags) != 0) {
1889 strlcpy(hbuf, "(invalid)", sizeof(hbuf));
1890 }
1891 fprintf(stderr(&__sF[2]), "telnet: connect to address %s: %s\n", hbuf,
1892 strerror(errno(*__errno())));
1893
1894 close(net);
1895 net = -1;
1896 retry++;
1897 continue;
1898 }
1899
1900 connected++;
1901 break;
1902 }
1903 freeaddrinfo(res0);
1904 if (net < 0) {
1905 return 0;
1906 }
1907 cmdrc(hostp, hostname);
1908 if (autologin && user == NULL((void *)0)) {
1909 struct passwd *pw;
1910
1911 user = getlogin();
1912 if (user == NULL((void *)0) ||
1913 (pw = getpwnam(user)) == NULL((void *)0) || pw->pw_uid != getuid()) {
1914 if ((pw = getpwuid(getuid())) != NULL((void *)0))
1915 user = pw->pw_name;
1916 else
1917 user = NULL((void *)0);
1918 }
1919 }
1920 if (user) {
1921 env_define("USER", user);
1922 env_export("USER");
1923 }
1924 connection_status(1);
1925 if (setjmp(peerdied) == 0)
1926 telnet(user);
1927 (void)close(net);
1928 ExitString("Connection closed by foreign host.\r\n",1);
1929}
1930
1931#define HELPINDENT(sizeof ("connect")) (sizeof ("connect"))
1932
1933static char
1934 openhelp[] = "connect to a site",
1935 closehelp[] = "close current connection",
1936 logouthelp[] = "forcibly logout remote user and close the connection",
1937 quithelp[] = "exit telnet",
1938 statushelp[] = "print status information",
1939 helphelp[] = "print help information",
1940 sendhelp[] = "transmit special characters ('send ?' for more)",
1941 sethelp[] = "set operating parameters ('set ?' for more)",
1942 unsethelp[] = "unset operating parameters ('unset ?' for more)",
1943 togglestring[] ="toggle operating parameters ('toggle ?' for more)",
1944 slchelp[] = "change state of special charaters ('slc ?' for more)",
1945 displayhelp[] = "display operating parameters",
1946 zhelp[] = "suspend telnet",
1947 envhelp[] = "change environment variables ('environ ?' for more)",
1948 modestring[] = "try to enter line or character mode ('mode ?' for more)";
1949
1950static int help(int, char**);
1951
1952static Command cmdtab[] = {
1953 { "close", closehelp, bye, 1 },
1954 { "logout", logouthelp, logout, 1 },
1955 { "display", displayhelp, display, 0 },
1956 { "mode", modestring, modecmd, 0 },
1957 { "open", openhelp, tn, 0 },
1958 { "quit", quithelp, quitcmd, 0 },
1959 { "send", sendhelp, sendcmd, 0 },
1960 { "set", sethelp, setcmd, 0 },
1961 { "unset", unsethelp, unsetcmd, 0 },
1962 { "status", statushelp, status, 0 },
1963 { "toggle", togglestring, toggle, 0 },
1964 { "slc", slchelp, slccmd, 0 },
1965
1966 { "z", zhelp, telnetsuspend, 0 },
1967 { "environ", envhelp, env_cmd, 0 },
1968 { "?", helphelp, help, 0 },
1969 { 0, 0, 0, 0 }
1970};
1971
1972static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead";
1973static char escapehelp[] = "deprecated command -- use 'set escape' instead";
1974
1975static Command cmdtab2[] = {
1976 { "help", 0, help, 0 },
1977 { "escape", escapehelp, setescape, 0 },
1978 { "crmod", crmodhelp, togcrmod, 0 },
1979 { 0, 0, 0, 0 }
1980};
1981
1982
1983static Command *
1984getcmd(char *name)
1985{
1986 Command *cm;
1987
1988 if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))))
1989 return cm;
1990 return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
1991}
1992
1993void
1994command(int top, char *tbuf, int cnt)
1995{
1996 Command *c;
1997
1998 setcommandmode();
1999 if (!top) {
2000 putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
2001 } else {
2002 (void) signal(SIGINT2, SIG_DFL(void (*)(int))0);
2003 (void) signal(SIGQUIT3, SIG_DFL(void (*)(int))0);
2004 }
2005 for (;;) {
2006 if (rlogin == _POSIX_VDISABLE(0377))
2007 printf("%s> ", prompt);
2008 if (tbuf) {
2009 char *cp;
2010 cp = line;
2011 while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
2012 cnt--;
2013 tbuf = 0;
2014 if (cp == line || *--cp != '\n' || cp == line)
2015 goto getline;
2016 *cp = '\0';
2017 if (rlogin == _POSIX_VDISABLE(0377))
2018 printf("%s\r\n", line);
2019 } else {
2020 getline:
2021 if (rlogin != _POSIX_VDISABLE(0377))
2022 printf("%s> ", prompt);
2023 if (fgets(line, sizeof(line), stdin(&__sF[0])) == NULL((void *)0)) {
2024 if (feof(stdin)(!__isthreaded ? ((((&__sF[0]))->_flags & 0x0020) !=
0) : (feof)((&__sF[0])))
|| ferror(stdin)(!__isthreaded ? ((((&__sF[0]))->_flags & 0x0040) !=
0) : (ferror)((&__sF[0])))
)
2025 quit();
2026 break;
2027 }
2028 }
2029 if (line[0] == 0)
2030 break;
2031 if (makeargv())
2032 break;
2033 if (margv[0] == 0) {
2034 break;
2035 }
2036 c = getcmd(margv[0]);
2037 if (Ambiguous(c)) {
2038 printf("?Ambiguous command\r\n");
2039 continue;
2040 }
2041 if (c == 0) {
2042 printf("?Invalid command\r\n");
2043 continue;
2044 }
2045 if (c->needconnect && !connected) {
2046 printf("?Need to be connected first.\r\n");
2047 continue;
2048 }
2049 if ((*c->handler)(margc, margv)) {
2050 break;
2051 }
2052 }
2053 if (!top) {
2054 if (!connected)
2055 longjmp(toplevel, 1);
2056 setconnmode(0);
2057 }
2058}
2059
2060/*
2061 * Help command.
2062 */
2063static int
2064help(int argc, char *argv[])
2065{
2066 Command *c;
2067
2068 if (argc == 1) {
2069 printf("Commands may be abbreviated. Commands are:\r\n\r\n");
2070 for (c = cmdtab; c->name; c++)
2071 if (c->help) {
2072 printf("%-*s\t%s\r\n", (int)HELPINDENT(sizeof ("connect")), c->name,
2073 c->help);
2074 }
2075 return 0;
2076 }
2077 while (--argc > 0) {
2078 char *arg;
2079 arg = *++argv;
2080 c = getcmd(arg);
2081 if (Ambiguous(c))
2082 printf("?Ambiguous help command %s\r\n", arg);
2083 else if (c == NULL((void *)0))
2084 printf("?Invalid help command %s\r\n", arg);
2085 else
2086 printf("%s\r\n", c->help);
2087 }
2088 return 0;
2089}