]> git.cameronkatri.com Git - apple_cmds.git/blob - remote_cmds/telnet.tproj/commands.c
file_cmds: 321.100.10.0.1
[apple_cmds.git] / remote_cmds / telnet.tproj / commands.c
1 /*
2 * Copyright (c) 1988, 1990, 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 #if 0
35 #ifndef lint
36 static const char sccsid[] = "@(#)commands.c 8.4 (Berkeley) 5/30/95";
37 #endif
38 #endif
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD: src/contrib/telnet/telnet/commands.c,v 1.35 2005/02/28 12:46:52 tobez Exp $");
41
42 /* Use RFC 2292 constants in <netinet6/in6.h> */
43 #define __APPLE_USE_RFC_2292
44
45 #include <sys/param.h>
46 #include <sys/un.h>
47 #include <sys/file.h>
48 #include <sys/socket.h>
49 #include <netinet/in.h>
50
51 #include <ctype.h>
52 #include <err.h>
53 #include <errno.h>
54 #include <netdb.h>
55 #include <pwd.h>
56 #include <signal.h>
57 #include <stdarg.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <unistd.h>
61
62 #include <arpa/telnet.h>
63 #include <arpa/inet.h>
64
65 #include "general.h"
66
67 #include "ring.h"
68
69 #include "externs.h"
70 #include "defines.h"
71 #include "types.h"
72 #include "misc.h"
73
74 #ifdef AUTHENTICATION
75 #include <libtelnet/auth.h>
76 #endif
77 #ifdef ENCRYPTION
78 #include <libtelnet/encrypt.h>
79 #endif
80
81 #include <netinet/in_systm.h>
82 #include <netinet/ip.h>
83 #include <netinet/ip6.h>
84
85 #ifndef MAXHOSTNAMELEN
86 #define MAXHOSTNAMELEN 256
87 #endif
88
89 typedef int (*intrtn_t)(int, char **);
90
91 #ifdef AUTHENTICATION
92 extern int auth_togdebug(int);
93 #endif
94 #ifdef ENCRYPTION
95 extern int EncryptAutoEnc(int);
96 extern int EncryptAutoDec(int);
97 extern int EncryptDebug(int);
98 extern int EncryptVerbose(int);
99 #endif /* ENCRYPTION */
100 #if defined(IPPROTO_IP) && defined(IP_TOS)
101 int tos = -1;
102 #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
103
104 char *hostname;
105 static char _hostname[MAXHOSTNAMELEN];
106
107 static int help(int, char **);
108 static int call(intrtn_t, ...);
109 static void cmdrc(char *, char *);
110 #ifdef INET6
111 static int switch_af(struct addrinfo **);
112 #endif
113 static int togglehelp(void);
114 static int send_tncmd(void (*)(int, int), const char *, char *);
115 static int setmod(int);
116 static int clearmode(int);
117 static int modehelp(void);
118 #ifndef __APPLE__
119 static int sourceroute(struct addrinfo *, char *, char **, int *, int *, int *);
120 #endif
121
122 typedef struct {
123 const char *name; /* command name */
124 const char *help; /* help string (NULL for no help) */
125 int (*handler)(int, char **); /* routine which executes command */
126 int needconnect; /* Do we need to be connected to execute? */
127 } Command;
128
129 static char line[256];
130 static char saveline[256];
131 static int margc;
132 static char *margv[20];
133
134 #ifdef OPIE
135 #include <sys/wait.h>
136 #define PATH_OPIEKEY "/usr/bin/opiekey"
137 static int
138 opie_calc(int argc, char *argv[])
139 {
140 int status;
141
142 if(argc != 3) {
143 printf("%s sequence challenge\n", argv[0]);
144 return (0);
145 }
146
147 switch(fork()) {
148 case 0:
149 execv(PATH_OPIEKEY, argv);
150 exit (1);
151 case -1:
152 perror("fork");
153 break;
154 default:
155 (void) wait(&status);
156 if (WIFEXITED(status))
157 return (WEXITSTATUS(status));
158 }
159 return (0);
160 }
161 #endif
162
163 static void
164 makeargv(void)
165 {
166 char *cp, *cp2, c;
167 char **argp = margv;
168
169 margc = 0;
170 cp = line;
171 if (*cp == '!') { /* Special case shell escape */
172 strcpy(saveline, line); /* save for shell command */
173 *argp++ = strdup("!"); /* No room in string to get this */
174 margc++;
175 cp++;
176 }
177 while ((c = *cp)) {
178 int inquote = 0;
179 while (isspace(c))
180 c = *++cp;
181 if (c == '\0')
182 break;
183 *argp++ = cp;
184 margc += 1;
185 for (cp2 = cp; c != '\0'; c = *++cp) {
186 if (inquote) {
187 if (c == inquote) {
188 inquote = 0;
189 continue;
190 }
191 } else {
192 if (c == '\\') {
193 if ((c = *++cp) == '\0')
194 break;
195 } else if (c == '"') {
196 inquote = '"';
197 continue;
198 } else if (c == '\'') {
199 inquote = '\'';
200 continue;
201 } else if (isspace(c))
202 break;
203 }
204 *cp2++ = c;
205 }
206 *cp2 = '\0';
207 if (c == '\0')
208 break;
209 cp++;
210 }
211 *argp++ = 0;
212 }
213
214 /*
215 * Make a character string into a number.
216 *
217 * Todo: 1. Could take random integers (12, 0x12, 012, 0b1).
218 */
219
220 static int
221 special(char *s)
222 {
223 char c;
224 char b;
225
226 switch (*s) {
227 case '^':
228 b = *++s;
229 if (b == '?') {
230 c = b | 0x40; /* DEL */
231 } else {
232 c = b & 0x1f;
233 }
234 break;
235 default:
236 c = *s;
237 break;
238 }
239 return c;
240 }
241
242 /*
243 * Construct a control character sequence
244 * for a special character.
245 */
246 static const char *
247 control(cc_t c)
248 {
249 static char buf[5];
250 /*
251 * The only way I could get the Sun 3.5 compiler
252 * to shut up about
253 * if ((unsigned int)c >= 0x80)
254 * was to assign "c" to an unsigned int variable...
255 * Arggg....
256 */
257 unsigned int uic = (unsigned int)c;
258
259 if (uic == 0x7f)
260 return ("^?");
261 if (c == (cc_t)_POSIX_VDISABLE) {
262 return "off";
263 }
264 if (uic >= 0x80) {
265 buf[0] = '\\';
266 buf[1] = ((c>>6)&07) + '0';
267 buf[2] = ((c>>3)&07) + '0';
268 buf[3] = (c&07) + '0';
269 buf[4] = 0;
270 } else if (uic >= 0x20) {
271 buf[0] = c;
272 buf[1] = 0;
273 } else {
274 buf[0] = '^';
275 buf[1] = '@'+c;
276 buf[2] = 0;
277 }
278 return (buf);
279 }
280
281 /*
282 * The following are data structures and routines for
283 * the "send" command.
284 *
285 */
286
287 struct sendlist {
288 const char *name; /* How user refers to it (case independent) */
289 const char *help; /* Help information (0 ==> no help) */
290 int needconnect; /* Need to be connected */
291 int narg; /* Number of arguments */
292 int (*handler)(char *, ...); /* Routine to perform (for special ops) */
293 int nbyte; /* Number of bytes to send this command */
294 int what; /* Character to be sent (<0 ==> special) */
295 };
296 \f
297
298 static int
299 send_esc(void),
300 send_help(void),
301 send_docmd(char *),
302 send_dontcmd(char *),
303 send_willcmd(char *),
304 send_wontcmd(char *);
305
306 static struct sendlist Sendlist[] = {
307 { "ao", "Send Telnet Abort output", 1, 0, NULL, 2, AO },
308 { "ayt", "Send Telnet 'Are You There'", 1, 0, NULL, 2, AYT },
309 { "brk", "Send Telnet Break", 1, 0, NULL, 2, BREAK },
310 { "break", NULL, 1, 0, NULL, 2, BREAK },
311 { "ec", "Send Telnet Erase Character", 1, 0, NULL, 2, EC },
312 { "el", "Send Telnet Erase Line", 1, 0, NULL, 2, EL },
313 { "escape", "Send current escape character",1, 0, (int (*)(char *, ...))send_esc, 1, 0 },
314 { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, NULL, 2, GA },
315 { "ip", "Send Telnet Interrupt Process",1, 0, NULL, 2, IP },
316 { "intp", NULL, 1, 0, NULL, 2, IP },
317 { "interrupt", NULL, 1, 0, NULL, 2, IP },
318 { "intr", NULL, 1, 0, NULL, 2, IP },
319 { "nop", "Send Telnet 'No operation'", 1, 0, NULL, 2, NOP },
320 { "eor", "Send Telnet 'End of Record'", 1, 0, NULL, 2, EOR },
321 { "abort", "Send Telnet 'Abort Process'", 1, 0, NULL, 2, ABORT },
322 { "susp", "Send Telnet 'Suspend Process'",1, 0, NULL, 2, SUSP },
323 { "eof", "Send Telnet End of File Character", 1, 0, NULL, 2, xEOF },
324 { "synch", "Perform Telnet 'Synch operation'", 1, 0, (int (*)(char *, ...))dosynch, 2, 0 },
325 { "getstatus", "Send request for STATUS", 1, 0, (int (*)(char *, ...))get_status, 6, 0 },
326 { "?", "Display send options", 0, 0, (int (*)(char *, ...))send_help, 0, 0 },
327 { "help", NULL, 0, 0, (int (*)(char *, ...))send_help, 0, 0 },
328 { "do", NULL, 0, 1, (int (*)(char *, ...))send_docmd, 3, 0 },
329 { "dont", NULL, 0, 1, (int (*)(char *, ...))send_dontcmd, 3, 0 },
330 { "will", NULL, 0, 1, (int (*)(char *, ...))send_willcmd, 3, 0 },
331 { "wont", NULL, 0, 1, (int (*)(char *, ...))send_wontcmd, 3, 0 },
332 { NULL, NULL, 0, 0, NULL, 0, 0 }
333 };
334
335 #define GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \
336 sizeof(struct sendlist)))
337
338 static int
339 sendcmd(int argc, char *argv[])
340 {
341 int count; /* how many bytes we are going to need to send */
342 int i;
343 struct sendlist *s; /* pointer to current command */
344 int success = 0;
345 int needconnect = 0;
346
347 if (argc < 2) {
348 printf("need at least one argument for 'send' command\n");
349 printf("'send ?' for help\n");
350 return 0;
351 }
352 /*
353 * First, validate all the send arguments.
354 * In addition, we see how much space we are going to need, and
355 * whether or not we will be doing a "SYNCH" operation (which
356 * flushes the network queue).
357 */
358 count = 0;
359 for (i = 1; i < argc; i++) {
360 s = GETSEND(argv[i]);
361 if (s == 0) {
362 printf("Unknown send argument '%s'\n'send ?' for help.\n",
363 argv[i]);
364 return 0;
365 } else if (Ambiguous((void *)s)) {
366 printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
367 argv[i]);
368 return 0;
369 }
370 if (i + s->narg >= argc) {
371 fprintf(stderr,
372 "Need %d argument%s to 'send %s' command. 'send %s ?' for help.\n",
373 s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
374 return 0;
375 }
376 count += s->nbyte;
377 if ((void *)s->handler == (void *)send_help) {
378 send_help();
379 return 0;
380 }
381
382 i += s->narg;
383 needconnect += s->needconnect;
384 }
385 if (!connected && needconnect) {
386 printf("?Need to be connected first.\n");
387 printf("'send ?' for help\n");
388 return 0;
389 }
390 /* Now, do we have enough room? */
391 if (NETROOM() < count) {
392 printf("There is not enough room in the buffer TO the network\n");
393 printf("to process your request. Nothing will be done.\n");
394 printf("('send synch' will throw away most data in the network\n");
395 printf("buffer, if this might help.)\n");
396 return 0;
397 }
398 /* OK, they are all OK, now go through again and actually send */
399 count = 0;
400 for (i = 1; i < argc; i++) {
401 if ((s = GETSEND(argv[i])) == 0) {
402 fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
403 quit();
404 /*NOTREACHED*/
405 }
406 if (s->handler) {
407 count++;
408 success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0,
409 (s->narg > 1) ? argv[i+2] : 0);
410 i += s->narg;
411 } else {
412 NET2ADD(IAC, s->what);
413 printoption("SENT", IAC, s->what);
414 }
415 }
416 return (count == success);
417 }
418
419 static int
420 send_esc(void)
421 {
422 NETADD(escape);
423 return 1;
424 }
425
426 static int
427 send_docmd(char *name)
428 {
429 return(send_tncmd(send_do, "do", name));
430 }
431
432 static int
433 send_dontcmd(name)
434 char *name;
435 {
436 return(send_tncmd(send_dont, "dont", name));
437 }
438
439 static int
440 send_willcmd(char *name)
441 {
442 return(send_tncmd(send_will, "will", name));
443 }
444
445 static int
446 send_wontcmd(char *name)
447 {
448 return(send_tncmd(send_wont, "wont", name));
449 }
450
451 static int
452 send_tncmd(void (*func)(int, int), const char *cmd, char *name)
453 {
454 char **cpp;
455 extern char *telopts[];
456 int val = 0;
457
458 if (isprefix(name, "help") || isprefix(name, "?")) {
459 int col, len;
460
461 printf("usage: send %s <value|option>\n", cmd);
462 printf("\"value\" must be from 0 to 255\n");
463 printf("Valid options are:\n\t");
464
465 col = 8;
466 for (cpp = telopts; *cpp; cpp++) {
467 len = strlen(*cpp) + 3;
468 if (col + len > 65) {
469 printf("\n\t");
470 col = 8;
471 }
472 printf(" \"%s\"", *cpp);
473 col += len;
474 }
475 printf("\n");
476 return 0;
477 }
478 cpp = (char **)genget(name, telopts, sizeof(char *));
479 if (Ambiguous(cpp)) {
480 fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\n",
481 name, cmd);
482 return 0;
483 }
484 if (cpp) {
485 val = cpp - telopts;
486 } else {
487 char *cp = name;
488
489 while (*cp >= '0' && *cp <= '9') {
490 val *= 10;
491 val += *cp - '0';
492 cp++;
493 }
494 if (*cp != 0) {
495 fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n",
496 name, cmd);
497 return 0;
498 } else if (val < 0 || val > 255) {
499 fprintf(stderr, "'%s': bad value ('send %s ?' for help).\n",
500 name, cmd);
501 return 0;
502 }
503 }
504 if (!connected) {
505 printf("?Need to be connected first.\n");
506 return 0;
507 }
508 (*func)(val, 1);
509 return 1;
510 }
511
512 static int
513 send_help(void)
514 {
515 struct sendlist *s; /* pointer to current command */
516 for (s = Sendlist; s->name; s++) {
517 if (s->help)
518 printf("%-15s %s\n", s->name, s->help);
519 }
520 return(0);
521 }
522 \f
523 /*
524 * The following are the routines and data structures referred
525 * to by the arguments to the "toggle" command.
526 */
527
528 static int
529 lclchars(void)
530 {
531 donelclchars = 1;
532 return 1;
533 }
534
535 static int
536 togdebug(void)
537 {
538 #ifndef NOT43
539 if (net > 0 &&
540 (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, telnet_debug)) < 0) {
541 perror("setsockopt (SO_DEBUG)");
542 }
543 #else /* NOT43 */
544 if (telnet_debug) {
545 if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0)
546 perror("setsockopt (SO_DEBUG)");
547 } else
548 printf("Cannot turn off socket debugging\n");
549 #endif /* NOT43 */
550 return 1;
551 }
552
553
554 static int
555 togcrlf(void)
556 {
557 if (crlf) {
558 printf("Will send carriage returns as telnet <CR><LF>.\n");
559 } else {
560 printf("Will send carriage returns as telnet <CR><NUL>.\n");
561 }
562 return 1;
563 }
564
565 int binmode;
566
567 static int
568 togbinary(int val)
569 {
570 donebinarytoggle = 1;
571
572 if (val >= 0) {
573 binmode = val;
574 } else {
575 if (my_want_state_is_will(TELOPT_BINARY) &&
576 my_want_state_is_do(TELOPT_BINARY)) {
577 binmode = 1;
578 } else if (my_want_state_is_wont(TELOPT_BINARY) &&
579 my_want_state_is_dont(TELOPT_BINARY)) {
580 binmode = 0;
581 }
582 val = binmode ? 0 : 1;
583 }
584
585 if (val == 1) {
586 if (my_want_state_is_will(TELOPT_BINARY) &&
587 my_want_state_is_do(TELOPT_BINARY)) {
588 printf("Already operating in binary mode with remote host.\n");
589 } else {
590 printf("Negotiating binary mode with remote host.\n");
591 tel_enter_binary(3);
592 }
593 } else {
594 if (my_want_state_is_wont(TELOPT_BINARY) &&
595 my_want_state_is_dont(TELOPT_BINARY)) {
596 printf("Already in network ascii mode with remote host.\n");
597 } else {
598 printf("Negotiating network ascii mode with remote host.\n");
599 tel_leave_binary(3);
600 }
601 }
602 return 1;
603 }
604
605 static int
606 togrbinary(int val)
607 {
608 donebinarytoggle = 1;
609
610 if (val == -1)
611 val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
612
613 if (val == 1) {
614 if (my_want_state_is_do(TELOPT_BINARY)) {
615 printf("Already receiving in binary mode.\n");
616 } else {
617 printf("Negotiating binary mode on input.\n");
618 tel_enter_binary(1);
619 }
620 } else {
621 if (my_want_state_is_dont(TELOPT_BINARY)) {
622 printf("Already receiving in network ascii mode.\n");
623 } else {
624 printf("Negotiating network ascii mode on input.\n");
625 tel_leave_binary(1);
626 }
627 }
628 return 1;
629 }
630
631 static int
632 togxbinary(int val)
633 {
634 donebinarytoggle = 1;
635
636 if (val == -1)
637 val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
638
639 if (val == 1) {
640 if (my_want_state_is_will(TELOPT_BINARY)) {
641 printf("Already transmitting in binary mode.\n");
642 } else {
643 printf("Negotiating binary mode on output.\n");
644 tel_enter_binary(2);
645 }
646 } else {
647 if (my_want_state_is_wont(TELOPT_BINARY)) {
648 printf("Already transmitting in network ascii mode.\n");
649 } else {
650 printf("Negotiating network ascii mode on output.\n");
651 tel_leave_binary(2);
652 }
653 }
654 return 1;
655 }
656
657 struct togglelist {
658 const char *name; /* name of toggle */
659 const char *help; /* help message */
660 int (*handler)(int); /* routine to do actual setting */
661 int *variable;
662 const char *actionexplanation;
663 };
664
665 static struct togglelist Togglelist[] = {
666 { "autoflush",
667 "flushing of output when sending interrupt characters",
668 0,
669 &autoflush,
670 "flush output when sending interrupt characters" },
671 { "autosynch",
672 "automatic sending of interrupt characters in urgent mode",
673 0,
674 &autosynch,
675 "send interrupt characters in urgent mode" },
676 #ifdef AUTHENTICATION
677 { "autologin",
678 "automatic sending of login and/or authentication info",
679 0,
680 &autologin,
681 "send login name and/or authentication information" },
682 { "authdebug",
683 "Toggle authentication debugging",
684 auth_togdebug,
685 0,
686 "print authentication debugging information" },
687 #endif
688 #ifdef ENCRYPTION
689 { "autoencrypt",
690 "automatic encryption of data stream",
691 EncryptAutoEnc,
692 0,
693 "automatically encrypt output" },
694 { "autodecrypt",
695 "automatic decryption of data stream",
696 EncryptAutoDec,
697 0,
698 "automatically decrypt input" },
699 { "verbose_encrypt",
700 "Toggle verbose encryption output",
701 EncryptVerbose,
702 0,
703 "print verbose encryption output" },
704 { "encdebug",
705 "Toggle encryption debugging",
706 EncryptDebug,
707 0,
708 "print encryption debugging information" },
709 #endif /* ENCRYPTION */
710 { "skiprc",
711 "don't read ~/.telnetrc file",
712 0,
713 &skiprc,
714 "skip reading of ~/.telnetrc file" },
715 { "binary",
716 "sending and receiving of binary data",
717 togbinary,
718 0,
719 0 },
720 { "inbinary",
721 "receiving of binary data",
722 togrbinary,
723 0,
724 0 },
725 { "outbinary",
726 "sending of binary data",
727 togxbinary,
728 0,
729 0 },
730 { "crlf",
731 "sending carriage returns as telnet <CR><LF>",
732 (int (*)(int))togcrlf,
733 &crlf,
734 0 },
735 { "crmod",
736 "mapping of received carriage returns",
737 0,
738 &crmod,
739 "map carriage return on output" },
740 { "localchars",
741 "local recognition of certain control characters",
742 (int (*)(int))lclchars,
743 &localchars,
744 "recognize certain control characters" },
745 { " ", "", NULL, NULL, NULL }, /* empty line */
746 { "debug",
747 "debugging",
748 (int (*)(int))togdebug,
749 &telnet_debug,
750 "turn on socket level debugging" },
751 { "netdata",
752 "printing of hexadecimal network data (debugging)",
753 0,
754 &netdata,
755 "print hexadecimal representation of network traffic" },
756 { "prettydump",
757 "output of \"netdata\" to user readable format (debugging)",
758 0,
759 &prettydump,
760 "print user readable output for \"netdata\"" },
761 { "options",
762 "viewing of options processing (debugging)",
763 0,
764 &showoptions,
765 "show option processing" },
766 { "termdata",
767 "(debugging) toggle printing of hexadecimal terminal data",
768 0,
769 &termdata,
770 "print hexadecimal representation of terminal traffic" },
771 { "?",
772 NULL,
773 (int (*)(int))togglehelp,
774 NULL,
775 NULL },
776 { NULL, NULL, NULL, NULL, NULL },
777 { "help",
778 NULL,
779 (int (*)(int))togglehelp,
780 NULL,
781 NULL },
782 { NULL, NULL, NULL, NULL, NULL }
783 };
784
785 static int
786 togglehelp(void)
787 {
788 struct togglelist *c;
789
790 for (c = Togglelist; c->name; c++) {
791 if (c->help) {
792 if (*c->help)
793 printf("%-15s toggle %s\n", c->name, c->help);
794 else
795 printf("\n");
796 }
797 }
798 printf("\n");
799 printf("%-15s %s\n", "?", "display help information");
800 return 0;
801 }
802
803 static void
804 settogglehelp(int set)
805 {
806 struct togglelist *c;
807
808 for (c = Togglelist; c->name; c++) {
809 if (c->help) {
810 if (*c->help)
811 printf("%-15s %s %s\n", c->name, set ? "enable" : "disable",
812 c->help);
813 else
814 printf("\n");
815 }
816 }
817 }
818
819 #define GETTOGGLE(name) (struct togglelist *) \
820 genget(name, (char **) Togglelist, sizeof(struct togglelist))
821
822 static int
823 toggle(int argc, char *argv[])
824 {
825 int retval = 1;
826 char *name;
827 struct togglelist *c;
828
829 if (argc < 2) {
830 fprintf(stderr,
831 "Need an argument to 'toggle' command. 'toggle ?' for help.\n");
832 return 0;
833 }
834 argc--;
835 argv++;
836 while (argc--) {
837 name = *argv++;
838 c = GETTOGGLE(name);
839 if (Ambiguous((void *)c)) {
840 fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
841 name);
842 return 0;
843 } else if (c == 0) {
844 fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
845 name);
846 return 0;
847 } else {
848 if (c->variable) {
849 *c->variable = !*c->variable; /* invert it */
850 if (c->actionexplanation) {
851 printf("%s %s.\n", *c->variable? "Will" : "Won't",
852 c->actionexplanation);
853 }
854 }
855 if (c->handler) {
856 retval &= (*c->handler)(-1);
857 }
858 }
859 }
860 return retval;
861 }
862 \f
863 /*
864 * The following perform the "set" command.
865 */
866
867 #ifdef USE_TERMIO
868 struct termio new_tc = { 0, 0, 0, 0, {}, 0, 0 };
869 #endif
870
871 struct setlist {
872 const char *name; /* name */
873 const char *help; /* help information */
874 void (*handler)(char *);
875 cc_t *charp; /* where it is located at */
876 };
877
878 static struct setlist Setlist[] = {
879 #ifdef KLUDGELINEMODE
880 { "echo", "character to toggle local echoing on/off", NULL, &echoc },
881 #endif
882 { "escape", "character to escape back to telnet command mode", NULL, &escape },
883 { "rlogin", "rlogin escape character", 0, &rlogin },
884 { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
885 { " ", "", NULL, NULL },
886 { " ", "The following need 'localchars' to be toggled true", NULL, NULL },
887 { "flushoutput", "character to cause an Abort Output", NULL, termFlushCharp },
888 { "interrupt", "character to cause an Interrupt Process", NULL, termIntCharp },
889 { "quit", "character to cause an Abort process", NULL, termQuitCharp },
890 { "eof", "character to cause an EOF ", NULL, termEofCharp },
891 { " ", "", NULL, NULL },
892 { " ", "The following are for local editing in linemode", NULL, NULL },
893 { "erase", "character to use to erase a character", NULL, termEraseCharp },
894 { "kill", "character to use to erase a line", NULL, termKillCharp },
895 { "lnext", "character to use for literal next", NULL, termLiteralNextCharp },
896 { "susp", "character to cause a Suspend Process", NULL, termSuspCharp },
897 { "reprint", "character to use for line reprint", NULL, termRprntCharp },
898 { "worderase", "character to use to erase a word", NULL, termWerasCharp },
899 { "start", "character to use for XON", NULL, termStartCharp },
900 { "stop", "character to use for XOFF", NULL, termStopCharp },
901 { "forw1", "alternate end of line character", NULL, termForw1Charp },
902 { "forw2", "alternate end of line character", NULL, termForw2Charp },
903 { "ayt", "alternate AYT character", NULL, termAytCharp },
904 { NULL, NULL, NULL, NULL }
905 };
906
907 static struct setlist *
908 getset(char *name)
909 {
910 return (struct setlist *)
911 genget(name, (char **) Setlist, sizeof(struct setlist));
912 }
913
914 void
915 set_escape_char(char *s)
916 {
917 if (rlogin != _POSIX_VDISABLE) {
918 rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
919 printf("Telnet rlogin escape character is '%s'.\n",
920 control(rlogin));
921 } else {
922 escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
923 printf("Telnet escape character is '%s'.\n", control(escape));
924 }
925 }
926
927 static int
928 setcmd(int argc, char *argv[])
929 {
930 int value;
931 struct setlist *ct;
932 struct togglelist *c;
933
934 if (argc < 2 || argc > 3) {
935 printf("Format is 'set Name Value'\n'set ?' for help.\n");
936 return 0;
937 }
938 if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
939 for (ct = Setlist; ct->name; ct++)
940 printf("%-15s %s\n", ct->name, ct->help);
941 printf("\n");
942 settogglehelp(1);
943 printf("%-15s %s\n", "?", "display help information");
944 return 0;
945 }
946
947 ct = getset(argv[1]);
948 if (ct == 0) {
949 c = GETTOGGLE(argv[1]);
950 if (c == 0) {
951 fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
952 argv[1]);
953 return 0;
954 } else if (Ambiguous((void *)c)) {
955 fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
956 argv[1]);
957 return 0;
958 }
959 if (c->variable) {
960 if ((argc == 2) || (strcmp("on", argv[2]) == 0))
961 *c->variable = 1;
962 else if (strcmp("off", argv[2]) == 0)
963 *c->variable = 0;
964 else {
965 printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
966 return 0;
967 }
968 if (c->actionexplanation) {
969 printf("%s %s.\n", *c->variable? "Will" : "Won't",
970 c->actionexplanation);
971 }
972 }
973 if (c->handler)
974 (*c->handler)(1);
975 } else if (argc != 3) {
976 printf("Format is 'set Name Value'\n'set ?' for help.\n");
977 return 0;
978 } else if (Ambiguous((void *)ct)) {
979 fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
980 argv[1]);
981 return 0;
982 } else if (ct->handler) {
983 (*ct->handler)(argv[2]);
984 printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp);
985 } else {
986 if (strcmp("off", argv[2])) {
987 value = special(argv[2]);
988 } else {
989 value = _POSIX_VDISABLE;
990 }
991 *(ct->charp) = (cc_t)value;
992 printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
993 }
994 slc_check();
995 return 1;
996 }
997
998 static int
999 unsetcmd(int argc, char *argv[])
1000 {
1001 struct setlist *ct;
1002 struct togglelist *c;
1003 char *name;
1004
1005 if (argc < 2) {
1006 fprintf(stderr,
1007 "Need an argument to 'unset' command. 'unset ?' for help.\n");
1008 return 0;
1009 }
1010 if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
1011 for (ct = Setlist; ct->name; ct++)
1012 printf("%-15s %s\n", ct->name, ct->help);
1013 printf("\n");
1014 settogglehelp(0);
1015 printf("%-15s %s\n", "?", "display help information");
1016 return 0;
1017 }
1018
1019 argc--;
1020 argv++;
1021 while (argc--) {
1022 name = *argv++;
1023 ct = getset(name);
1024 if (ct == 0) {
1025 c = GETTOGGLE(name);
1026 if (c == 0) {
1027 fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n",
1028 name);
1029 return 0;
1030 } else if (Ambiguous((void *)c)) {
1031 fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
1032 name);
1033 return 0;
1034 }
1035 if (c->variable) {
1036 *c->variable = 0;
1037 if (c->actionexplanation) {
1038 printf("%s %s.\n", *c->variable? "Will" : "Won't",
1039 c->actionexplanation);
1040 }
1041 }
1042 if (c->handler)
1043 (*c->handler)(0);
1044 } else if (Ambiguous((void *)ct)) {
1045 fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
1046 name);
1047 return 0;
1048 } else if (ct->handler) {
1049 (*ct->handler)(0);
1050 printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp);
1051 } else {
1052 *(ct->charp) = _POSIX_VDISABLE;
1053 printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
1054 }
1055 }
1056 return 1;
1057 }
1058 \f
1059 /*
1060 * The following are the data structures and routines for the
1061 * 'mode' command.
1062 */
1063 #ifdef KLUDGELINEMODE
1064 extern int kludgelinemode;
1065
1066 static int
1067 dokludgemode(void)
1068 {
1069 kludgelinemode = 1;
1070 send_wont(TELOPT_LINEMODE, 1);
1071 send_dont(TELOPT_SGA, 1);
1072 send_dont(TELOPT_ECHO, 1);
1073 return 1;
1074 }
1075 #endif
1076
1077 static int
1078 dolinemode(void)
1079 {
1080 #ifdef KLUDGELINEMODE
1081 if (kludgelinemode)
1082 send_dont(TELOPT_SGA, 1);
1083 #endif
1084 send_will(TELOPT_LINEMODE, 1);
1085 send_dont(TELOPT_ECHO, 1);
1086 return 1;
1087 }
1088
1089 static int
1090 docharmode(void)
1091 {
1092 #ifdef KLUDGELINEMODE
1093 if (kludgelinemode)
1094 send_do(TELOPT_SGA, 1);
1095 else
1096 #endif
1097 send_wont(TELOPT_LINEMODE, 1);
1098 send_do(TELOPT_ECHO, 1);
1099 return 1;
1100 }
1101
1102 static int
1103 dolmmode(int bit, int on)
1104 {
1105 unsigned char c;
1106 extern int linemode;
1107
1108 if (my_want_state_is_wont(TELOPT_LINEMODE)) {
1109 printf("?Need to have LINEMODE option enabled first.\n");
1110 printf("'mode ?' for help.\n");
1111 return 0;
1112 }
1113
1114 if (on)
1115 c = (linemode | bit);
1116 else
1117 c = (linemode & ~bit);
1118 lm_mode(&c, 1, 1);
1119 return 1;
1120 }
1121
1122 static int
1123 setmod(int bit)
1124 {
1125 return dolmmode(bit, 1);
1126 }
1127
1128 static int
1129 clearmode(int bit)
1130 {
1131 return dolmmode(bit, 0);
1132 }
1133
1134 struct modelist {
1135 const char *name; /* command name */
1136 const char *help; /* help string */
1137 int (*handler)(int);/* routine which executes command */
1138 int needconnect; /* Do we need to be connected to execute? */
1139 int arg1;
1140 };
1141
1142 static struct modelist ModeList[] = {
1143 { "character", "Disable LINEMODE option", (int (*)(int))docharmode, 1, 0 },
1144 #ifdef KLUDGELINEMODE
1145 { "", "(or disable obsolete line-by-line mode)", NULL, 0, 0 },
1146 #endif
1147 { "line", "Enable LINEMODE option", (int (*)(int))dolinemode, 1, 0 },
1148 #ifdef KLUDGELINEMODE
1149 { "", "(or enable obsolete line-by-line mode)", NULL, 0, 0 },
1150 #endif
1151 { "", "", NULL, 0, 0 },
1152 { "", "These require the LINEMODE option to be enabled", NULL, 0, 0 },
1153 { "isig", "Enable signal trapping", setmod, 1, MODE_TRAPSIG },
1154 { "+isig", 0, setmod, 1, MODE_TRAPSIG },
1155 { "-isig", "Disable signal trapping", clearmode, 1, MODE_TRAPSIG },
1156 { "edit", "Enable character editing", setmod, 1, MODE_EDIT },
1157 { "+edit", 0, setmod, 1, MODE_EDIT },
1158 { "-edit", "Disable character editing", clearmode, 1, MODE_EDIT },
1159 { "softtabs", "Enable tab expansion", setmod, 1, MODE_SOFT_TAB },
1160 { "+softtabs", 0, setmod, 1, MODE_SOFT_TAB },
1161 { "-softtabs", "Disable character editing", clearmode, 1, MODE_SOFT_TAB },
1162 { "litecho", "Enable literal character echo", setmod, 1, MODE_LIT_ECHO },
1163 { "+litecho", 0, setmod, 1, MODE_LIT_ECHO },
1164 { "-litecho", "Disable literal character echo", clearmode, 1, MODE_LIT_ECHO },
1165 { "help", 0, (int (*)(int))modehelp, 0, 0 },
1166 #ifdef KLUDGELINEMODE
1167 { "kludgeline", 0, (int (*)(int))dokludgemode, 1, 0 },
1168 #endif
1169 { "", "", NULL, 0, 0 },
1170 { "?", "Print help information", (int (*)(int))modehelp, 0, 0 },
1171 { NULL, NULL, NULL, 0, 0 },
1172 };
1173
1174
1175 static int
1176 modehelp(void)
1177 {
1178 struct modelist *mt;
1179
1180 printf("format is: 'mode Mode', where 'Mode' is one of:\n\n");
1181 for (mt = ModeList; mt->name; mt++) {
1182 if (mt->help) {
1183 if (*mt->help)
1184 printf("%-15s %s\n", mt->name, mt->help);
1185 else
1186 printf("\n");
1187 }
1188 }
1189 return 0;
1190 }
1191
1192 #define GETMODECMD(name) (struct modelist *) \
1193 genget(name, (char **) ModeList, sizeof(struct modelist))
1194
1195 static int
1196 modecmd(int argc, char *argv[])
1197 {
1198 struct modelist *mt;
1199
1200 if (argc != 2) {
1201 printf("'mode' command requires an argument\n");
1202 printf("'mode ?' for help.\n");
1203 } else if ((mt = GETMODECMD(argv[1])) == 0) {
1204 fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
1205 } else if (Ambiguous((void *)mt)) {
1206 fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
1207 } else if (mt->needconnect && !connected) {
1208 printf("?Need to be connected first.\n");
1209 printf("'mode ?' for help.\n");
1210 } else if (mt->handler) {
1211 return (*mt->handler)(mt->arg1);
1212 }
1213 return 0;
1214 }
1215 \f
1216 /*
1217 * The following data structures and routines implement the
1218 * "display" command.
1219 */
1220
1221 static int
1222 display(int argc, char *argv[])
1223 {
1224 struct togglelist *tl;
1225 struct setlist *sl;
1226
1227 #define dotog(tl) if (tl->variable && tl->actionexplanation) { \
1228 if (*tl->variable) { \
1229 printf("will"); \
1230 } else { \
1231 printf("won't"); \
1232 } \
1233 printf(" %s.\n", tl->actionexplanation); \
1234 }
1235
1236 #define doset(sl) if (sl->name && *sl->name != ' ') { \
1237 if (sl->handler == 0) \
1238 printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
1239 else \
1240 printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \
1241 }
1242
1243 if (argc == 1) {
1244 for (tl = Togglelist; tl->name; tl++) {
1245 dotog(tl);
1246 }
1247 printf("\n");
1248 for (sl = Setlist; sl->name; sl++) {
1249 doset(sl);
1250 }
1251 } else {
1252 int i;
1253
1254 for (i = 1; i < argc; i++) {
1255 sl = getset(argv[i]);
1256 tl = GETTOGGLE(argv[i]);
1257 if (Ambiguous((void *)sl) || Ambiguous((void *)tl)) {
1258 printf("?Ambiguous argument '%s'.\n", argv[i]);
1259 return 0;
1260 } else if (!sl && !tl) {
1261 printf("?Unknown argument '%s'.\n", argv[i]);
1262 return 0;
1263 } else {
1264 if (tl) {
1265 dotog(tl);
1266 }
1267 if (sl) {
1268 doset(sl);
1269 }
1270 }
1271 }
1272 }
1273 /*@*/optionstatus();
1274 #ifdef ENCRYPTION
1275 EncryptStatus();
1276 #endif /* ENCRYPTION */
1277 return 1;
1278 #undef doset
1279 #undef dotog
1280 }
1281 \f
1282 /*
1283 * The following are the data structures, and many of the routines,
1284 * relating to command processing.
1285 */
1286
1287 /*
1288 * Set the escape character.
1289 */
1290 static int
1291 setescape(int argc, char *argv[])
1292 {
1293 char *arg;
1294 char buf[50];
1295
1296 printf(
1297 "Deprecated usage - please use 'set escape%s%s' in the future.\n",
1298 (argc > 2)? " ":"", (argc > 2)? argv[1]: "");
1299 if (argc > 2)
1300 arg = argv[1];
1301 else {
1302 printf("new escape character: ");
1303 (void) fgets(buf, sizeof(buf), stdin);
1304 arg = buf;
1305 }
1306 if (arg[0] != '\0')
1307 escape = arg[0];
1308 (void) fflush(stdout);
1309 return 1;
1310 }
1311
1312 static int
1313 togcrmod(void)
1314 {
1315 crmod = !crmod;
1316 printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
1317 printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
1318 (void) fflush(stdout);
1319 return 1;
1320 }
1321
1322 static int
1323 suspend(void)
1324 {
1325 #ifdef SIGTSTP
1326 setcommandmode();
1327 {
1328 long oldrows, oldcols, newrows, newcols, err_;
1329
1330 err_ = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
1331 (void) kill(0, SIGTSTP);
1332 /*
1333 * If we didn't get the window size before the SUSPEND, but we
1334 * can get them now (?), then send the NAWS to make sure that
1335 * we are set up for the right window size.
1336 */
1337 if (TerminalWindowSize(&newrows, &newcols) && connected &&
1338 (err_ || ((oldrows != newrows) || (oldcols != newcols)))) {
1339 sendnaws();
1340 }
1341 }
1342 /* reget parameters in case they were changed */
1343 TerminalSaveState();
1344 setconnmode(0);
1345 #else
1346 printf("Suspend is not supported. Try the '!' command instead\n");
1347 #endif
1348 return 1;
1349 }
1350
1351 static int
1352 shell(int argc, char *argv[] __unused)
1353 {
1354 long oldrows, oldcols, newrows, newcols, err_;
1355
1356 setcommandmode();
1357
1358 err_ = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
1359 switch(vfork()) {
1360 case -1:
1361 perror("Fork failed\n");
1362 break;
1363
1364 case 0:
1365 {
1366 /*
1367 * Fire up the shell in the child.
1368 */
1369 const char *shellp, *shellname;
1370
1371 shellp = getenv("SHELL");
1372 if (shellp == NULL)
1373 shellp = "/bin/sh";
1374 if ((shellname = strrchr(shellp, '/')) == 0)
1375 shellname = shellp;
1376 else
1377 shellname++;
1378 if (argc > 1)
1379 execl(shellp, shellname, "-c", &saveline[1], (char *)0);
1380 else
1381 execl(shellp, shellname, (char *)0);
1382 perror("Execl");
1383 _exit(1);
1384 }
1385 default:
1386 (void)wait((int *)0); /* Wait for the shell to complete */
1387
1388 if (TerminalWindowSize(&newrows, &newcols) && connected &&
1389 (err_ || ((oldrows != newrows) || (oldcols != newcols)))) {
1390 sendnaws();
1391 }
1392 break;
1393 }
1394 return 1;
1395 }
1396
1397 static int
1398 bye(int argc, char *argv[])
1399 {
1400 extern int resettermname;
1401
1402 if (connected) {
1403 (void) shutdown(net, 2);
1404 printf("Connection closed.\n");
1405 (void) NetClose(net);
1406 connected = 0;
1407 resettermname = 1;
1408 #ifdef AUTHENTICATION
1409 #ifdef ENCRYPTION
1410 auth_encrypt_connect(connected);
1411 #endif
1412 #endif
1413 /* reset options */
1414 tninit();
1415 }
1416 if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
1417 longjmp(toplevel, 1);
1418 /* NOTREACHED */
1419 }
1420 return 1; /* Keep lint, etc., happy */
1421 }
1422
1423 void
1424 quit(void)
1425 {
1426 (void) call(bye, "bye", "fromquit", 0);
1427 Exit(0);
1428 }
1429
1430 static int
1431 logout(void)
1432 {
1433 send_do(TELOPT_LOGOUT, 1);
1434 (void) netflush();
1435 return 1;
1436 }
1437
1438 \f
1439 /*
1440 * The SLC command.
1441 */
1442
1443 struct slclist {
1444 const char *name;
1445 const char *help;
1446 void (*handler)(int);
1447 int arg;
1448 };
1449
1450 static void slc_help(void);
1451
1452 struct slclist SlcList[] = {
1453 { "export", "Use local special character definitions",
1454 (void (*)(int))slc_mode_export, 0 },
1455 { "import", "Use remote special character definitions",
1456 slc_mode_import, 1 },
1457 { "check", "Verify remote special character definitions",
1458 slc_mode_import, 0 },
1459 { "help", NULL, (void (*)(int))slc_help, 0 },
1460 { "?", "Print help information", (void (*)(int))slc_help, 0 },
1461 { NULL, NULL, NULL, 0 },
1462 };
1463
1464 static void
1465 slc_help(void)
1466 {
1467 struct slclist *c;
1468
1469 for (c = SlcList; c->name; c++) {
1470 if (c->help) {
1471 if (*c->help)
1472 printf("%-15s %s\n", c->name, c->help);
1473 else
1474 printf("\n");
1475 }
1476 }
1477 }
1478
1479 static struct slclist *
1480 getslc(char *name)
1481 {
1482 return (struct slclist *)
1483 genget(name, (char **) SlcList, sizeof(struct slclist));
1484 }
1485
1486 static int
1487 slccmd(int argc, char *argv[])
1488 {
1489 struct slclist *c;
1490
1491 if (argc != 2) {
1492 fprintf(stderr,
1493 "Need an argument to 'slc' command. 'slc ?' for help.\n");
1494 return 0;
1495 }
1496 c = getslc(argv[1]);
1497 if (c == 0) {
1498 fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
1499 argv[1]);
1500 return 0;
1501 }
1502 if (Ambiguous((void *)c)) {
1503 fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
1504 argv[1]);
1505 return 0;
1506 }
1507 (*c->handler)(c->arg);
1508 slcstate();
1509 return 1;
1510 }
1511 \f
1512 /*
1513 * The ENVIRON command.
1514 */
1515
1516 struct envlist {
1517 const char *name;
1518 const char *help;
1519 void (*handler)(unsigned char *, unsigned char *);
1520 int narg;
1521 };
1522
1523 extern struct env_lst *
1524 env_define(const unsigned char *, unsigned char *);
1525 extern void
1526 env_undefine(unsigned char *),
1527 env_export(const unsigned char *),
1528 env_unexport(const unsigned char *),
1529 env_send(unsigned char *),
1530 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
1531 env_varval(unsigned char *),
1532 #endif
1533 env_list(void);
1534 static void
1535 env_help(void);
1536
1537 struct envlist EnvList[] = {
1538 { "define", "Define an environment variable",
1539 (void (*)(unsigned char *, unsigned char *))env_define, 2 },
1540 { "undefine", "Undefine an environment variable",
1541 (void (*)(unsigned char *, unsigned char *))env_undefine, 1 },
1542 { "export", "Mark an environment variable for automatic export",
1543 (void (*)(unsigned char *, unsigned char *))env_export, 1 },
1544 { "unexport", "Don't mark an environment variable for automatic export",
1545 (void (*)(unsigned char *, unsigned char *))env_unexport, 1 },
1546 { "send", "Send an environment variable", (void (*)(unsigned char *, unsigned char *))env_send, 1 },
1547 { "list", "List the current environment variables",
1548 (void (*)(unsigned char *, unsigned char *))env_list, 0 },
1549 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
1550 { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)",
1551 (void (*)(unsigned char *, unsigned char *))env_varval, 1 },
1552 #endif
1553 { "help", NULL, (void (*)(unsigned char *, unsigned char *))env_help, 0 },
1554 { "?", "Print help information", (void (*)(unsigned char *, unsigned char *))env_help, 0 },
1555 { NULL, NULL, NULL, 0 },
1556 };
1557
1558 static void
1559 env_help(void)
1560 {
1561 struct envlist *c;
1562
1563 for (c = EnvList; c->name; c++) {
1564 if (c->help) {
1565 if (*c->help)
1566 printf("%-15s %s\n", c->name, c->help);
1567 else
1568 printf("\n");
1569 }
1570 }
1571 }
1572
1573 static struct envlist *
1574 getenvcmd(char *name)
1575 {
1576 return (struct envlist *)
1577 genget(name, (char **) EnvList, sizeof(struct envlist));
1578 }
1579
1580 static int
1581 env_cmd(int argc, char *argv[])
1582 {
1583 struct envlist *c;
1584
1585 if (argc < 2) {
1586 fprintf(stderr,
1587 "Need an argument to 'environ' command. 'environ ?' for help.\n");
1588 return 0;
1589 }
1590 c = getenvcmd(argv[1]);
1591 if (c == 0) {
1592 fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
1593 argv[1]);
1594 return 0;
1595 }
1596 if (Ambiguous((void *)c)) {
1597 fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
1598 argv[1]);
1599 return 0;
1600 }
1601 if (c->narg + 2 != argc && strcasecmp(argv[1],"define")==0 && c->narg + 1 != argc) {
1602 fprintf(stderr,
1603 "Need %s%d argument%s to 'environ %s' command. 'environ ?' for help.\n",
1604 c->narg < argc + 2 ? "only " : "",
1605 c->narg, c->narg == 1 ? "" : "s", c->name);
1606 return 0;
1607 }
1608 (*c->handler)((unsigned char *)argv[2], (unsigned char *)argv[3]);
1609 return 1;
1610 }
1611
1612 struct env_lst {
1613 struct env_lst *next; /* pointer to next structure */
1614 struct env_lst *prev; /* pointer to previous structure */
1615 unsigned char *var; /* pointer to variable name */
1616 unsigned char *value; /* pointer to variable value */
1617 int export; /* 1 -> export with default list of variables */
1618 int welldefined; /* A well defined variable */
1619 };
1620
1621 struct env_lst envlisthead;
1622
1623 static struct env_lst *
1624 env_find(const unsigned char *var)
1625 {
1626 struct env_lst *ep;
1627
1628 for (ep = envlisthead.next; ep; ep = ep->next) {
1629 if (strcmp((const char *)ep->var, (const char *)var) == 0)
1630 return(ep);
1631 }
1632 return(NULL);
1633 }
1634
1635 void
1636 env_init(void)
1637 {
1638 char *ev;
1639 struct env_lst *ep;
1640 int i;
1641
1642 const char *safe_vars[]=
1643 {"USER", "PRINTER", "DISPLAY", "TERM", "COLUMNS", "LINES"};
1644
1645 for(i=0;i<sizeof(safe_vars)/sizeof(const char *);i++) {
1646 if((ev=getenv(safe_vars[i]))) {
1647 ep=env_define((unsigned char *)safe_vars[i],(unsigned char *)ev);
1648 ep->export=0;
1649 }
1650 }
1651
1652 /*
1653 * Special case for DISPLAY variable. If it is ":0.0" or
1654 * "unix:0.0", we have to get rid of "unix" and insert our
1655 * hostname.
1656 */
1657 if ((ep = env_find((const unsigned char *)"DISPLAY"))
1658 && ((*ep->value == ':')
1659 || (strncmp((char *)ep->value, "unix:", 5) == 0))) {
1660 char hbuf[256+1];
1661 char *cp, *cp2 = strchr((char *)ep->value, ':');
1662
1663 gethostname(hbuf, 256);
1664 hbuf[256] = '\0';
1665 cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1);
1666 sprintf((char *)cp, "%s%s", hbuf, cp2);
1667 free(ep->value);
1668 ep->value = (unsigned char *)cp;
1669 }
1670 /*
1671 * If USER is not defined, but LOGNAME is, then add
1672 * USER with the value from LOGNAME. By default, we
1673 * don't export the USER variable.
1674 */
1675 if ((env_find((const unsigned char *)"USER") == NULL) && (ep = env_find((const unsigned char *)"LOGNAME"))) {
1676 env_define((const unsigned char *)"USER", ep->value);
1677 env_unexport((const unsigned char *)"USER");
1678 }
1679 env_export((const unsigned char *)"DISPLAY");
1680 env_export((const unsigned char *)"PRINTER");
1681 }
1682
1683 struct env_lst *
1684 env_define(const unsigned char *var, unsigned char *value)
1685 {
1686 char *ev;
1687 struct env_lst *ep;
1688
1689 if ((ep = env_find(var))) {
1690 if (ep->var)
1691 free(ep->var);
1692 if (ep->value)
1693 free(ep->value);
1694 } else {
1695 ep = (struct env_lst *)malloc(sizeof(struct env_lst));
1696 ep->next = envlisthead.next;
1697 envlisthead.next = ep;
1698 ep->prev = &envlisthead;
1699 if (ep->next)
1700 ep->next->prev = ep;
1701 }
1702
1703 ep->welldefined = opt_welldefined((const char *)var);
1704 ep->export = 1;
1705 ep->var = (unsigned char *)strdup((const char *)var);
1706
1707 if(value)
1708 ep->value = (unsigned char *)strdup((const char *)value);
1709 else if((ev=getenv((const char *)var)))
1710 ep->value = (unsigned char *)strdup(ev);
1711 else ep->value = (unsigned char *)strdup("");
1712 return(ep);
1713 }
1714
1715 void
1716 env_undefine(unsigned char *var)
1717 {
1718 struct env_lst *ep;
1719
1720 if ((ep = env_find(var))) {
1721 ep->prev->next = ep->next;
1722 if (ep->next)
1723 ep->next->prev = ep->prev;
1724 if (ep->var)
1725 free(ep->var);
1726 if (ep->value)
1727 free(ep->value);
1728 free(ep);
1729 }
1730 }
1731
1732 void
1733 env_export(const unsigned char *var)
1734 {
1735 struct env_lst *ep;
1736
1737 if ((ep = env_find(var)))
1738 ep->export = 1;
1739 }
1740
1741 void
1742 env_unexport(const unsigned char *var)
1743 {
1744 struct env_lst *ep;
1745
1746 if ((ep = env_find(var)))
1747 ep->export = 0;
1748 }
1749
1750 void
1751 env_send(unsigned char *var)
1752 {
1753 struct env_lst *ep;
1754
1755 if (my_state_is_wont(TELOPT_NEW_ENVIRON)
1756 #ifdef OLD_ENVIRON
1757 && my_state_is_wont(TELOPT_OLD_ENVIRON)
1758 #endif
1759 ) {
1760 fprintf(stderr,
1761 "Cannot send '%s': Telnet ENVIRON option not enabled\n",
1762 var);
1763 return;
1764 }
1765 ep = env_find(var);
1766 if (ep == 0) {
1767 fprintf(stderr, "Cannot send '%s': variable not defined\n",
1768 var);
1769 return;
1770 }
1771 env_opt_start_info();
1772 env_opt_add(ep->var);
1773 env_opt_end(0);
1774 }
1775
1776 void
1777 env_list(void)
1778 {
1779 struct env_lst *ep;
1780
1781 for (ep = envlisthead.next; ep; ep = ep->next) {
1782 printf("%c %-20s %s\n", ep->export ? '*' : ' ',
1783 ep->var, ep->value);
1784 }
1785 }
1786
1787 unsigned char *
1788 env_default(int init, int welldefined)
1789 {
1790 static struct env_lst *nep = NULL;
1791
1792 if (init) {
1793 nep = &envlisthead;
1794 return(NULL);
1795 }
1796 if (nep) {
1797 while ((nep = nep->next)) {
1798 if (nep->export && (nep->welldefined == welldefined))
1799 return(nep->var);
1800 }
1801 }
1802 return(NULL);
1803 }
1804
1805 unsigned char *
1806 env_getvalue(const unsigned char *var)
1807 {
1808 struct env_lst *ep;
1809
1810 if ((ep = env_find(var)))
1811 return(ep->value);
1812 return(NULL);
1813 }
1814
1815 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
1816 void
1817 env_varval(unsigned char *what)
1818 {
1819 extern int old_env_var, old_env_value, env_auto;
1820 int len = strlen((char *)what);
1821
1822 if (len == 0)
1823 goto unknown;
1824
1825 if (strncasecmp((char *)what, "status", len) == 0) {
1826 if (env_auto)
1827 printf("%s%s", "VAR and VALUE are/will be ",
1828 "determined automatically\n");
1829 if (old_env_var == OLD_ENV_VAR)
1830 printf("VAR and VALUE set to correct definitions\n");
1831 else
1832 printf("VAR and VALUE definitions are reversed\n");
1833 } else if (strncasecmp((char *)what, "auto", len) == 0) {
1834 env_auto = 1;
1835 old_env_var = OLD_ENV_VALUE;
1836 old_env_value = OLD_ENV_VAR;
1837 } else if (strncasecmp((char *)what, "right", len) == 0) {
1838 env_auto = 0;
1839 old_env_var = OLD_ENV_VAR;
1840 old_env_value = OLD_ENV_VALUE;
1841 } else if (strncasecmp((char *)what, "wrong", len) == 0) {
1842 env_auto = 0;
1843 old_env_var = OLD_ENV_VALUE;
1844 old_env_value = OLD_ENV_VAR;
1845 } else {
1846 unknown:
1847 printf("Unknown \"varval\" command. (\"auto\", \"right\", \"wrong\", \"status\")\n");
1848 }
1849 }
1850 #endif
1851
1852 #ifdef AUTHENTICATION
1853 /*
1854 * The AUTHENTICATE command.
1855 */
1856
1857 struct authlist {
1858 const char *name;
1859 const char *help;
1860 int (*handler)(char *);
1861 int narg;
1862 };
1863
1864 extern int
1865 auth_enable(char *),
1866 auth_disable(char *),
1867 auth_status(void);
1868 static int
1869 auth_help(void);
1870
1871 struct authlist AuthList[] = {
1872 { "status", "Display current status of authentication information",
1873 (int (*)(char *))auth_status, 0 },
1874 { "disable", "Disable an authentication type ('auth disable ?' for more)",
1875 auth_disable, 1 },
1876 { "enable", "Enable an authentication type ('auth enable ?' for more)",
1877 auth_enable, 1 },
1878 { "help", NULL, (int (*)(char *))auth_help, 0 },
1879 { "?", "Print help information", (int (*)(char *))auth_help, 0 },
1880 { NULL, NULL, NULL, 0 },
1881 };
1882
1883 static int
1884 auth_help(void)
1885 {
1886 struct authlist *c;
1887
1888 for (c = AuthList; c->name; c++) {
1889 if (c->help) {
1890 if (*c->help)
1891 printf("%-15s %s\n", c->name, c->help);
1892 else
1893 printf("\n");
1894 }
1895 }
1896 return 0;
1897 }
1898
1899 int
1900 auth_cmd(int argc, char *argv[])
1901 {
1902 struct authlist *c;
1903
1904 if (argc < 2) {
1905 fprintf(stderr,
1906 "Need an argument to 'auth' command. 'auth ?' for help.\n");
1907 return 0;
1908 }
1909
1910 c = (struct authlist *)
1911 genget(argv[1], (char **) AuthList, sizeof(struct authlist));
1912 if (c == 0) {
1913 fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n",
1914 argv[1]);
1915 return 0;
1916 }
1917 if (Ambiguous((void *)c)) {
1918 fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n",
1919 argv[1]);
1920 return 0;
1921 }
1922 if (c->narg + 2 != argc) {
1923 fprintf(stderr,
1924 "Need %s%d argument%s to 'auth %s' command. 'auth ?' for help.\n",
1925 c->narg < argc + 2 ? "only " : "",
1926 c->narg, c->narg == 1 ? "" : "s", c->name);
1927 return 0;
1928 }
1929 return((*c->handler)(argv[2]));
1930 }
1931 #endif
1932
1933 #ifdef ENCRYPTION
1934 /*
1935 * The ENCRYPT command.
1936 */
1937
1938 struct encryptlist {
1939 const char *name;
1940 const char *help;
1941 int (*handler)(char *, char *);
1942 int needconnect;
1943 int minarg;
1944 int maxarg;
1945 };
1946
1947 extern int
1948 EncryptEnable(char *, char *),
1949 EncryptDisable(char *, char *),
1950 EncryptType(char *, char *),
1951 EncryptStart(char *),
1952 EncryptStartInput(void),
1953 EncryptStartOutput(void),
1954 EncryptStop(char *),
1955 EncryptStopInput(void),
1956 EncryptStopOutput(void),
1957 EncryptStatus(void);
1958 static int
1959 EncryptHelp(void);
1960
1961 struct encryptlist EncryptList[] = {
1962 { "enable", "Enable encryption. ('encrypt enable ?' for more)",
1963 EncryptEnable, 1, 1, 2 },
1964 { "disable", "Disable encryption. ('encrypt enable ?' for more)",
1965 EncryptDisable, 0, 1, 2 },
1966 { "type", "Set encryption type. ('encrypt type ?' for more)",
1967 EncryptType, 0, 1, 1 },
1968 { "start", "Start encryption. ('encrypt start ?' for more)",
1969 (int (*)(char *, char *))EncryptStart, 1, 0, 1 },
1970 { "stop", "Stop encryption. ('encrypt stop ?' for more)",
1971 (int (*)(char *, char *))EncryptStop, 1, 0, 1 },
1972 { "input", "Start encrypting the input stream",
1973 (int (*)(char *, char *))EncryptStartInput, 1, 0, 0 },
1974 { "-input", "Stop encrypting the input stream",
1975 (int (*)(char *, char *))EncryptStopInput, 1, 0, 0 },
1976 { "output", "Start encrypting the output stream",
1977 (int (*)(char *, char *))EncryptStartOutput, 1, 0, 0 },
1978 { "-output", "Stop encrypting the output stream",
1979 (int (*)(char *, char *))EncryptStopOutput, 1, 0, 0 },
1980
1981 { "status", "Display current status of authentication information",
1982 (int (*)(char *, char *))EncryptStatus, 0, 0, 0 },
1983 { "help", NULL, (int (*)(char *, char *))EncryptHelp, 0, 0, 0 },
1984 { "?", "Print help information", (int (*)(char *, char *))EncryptHelp, 0, 0, 0 },
1985 { NULL, NULL, NULL, 0, 0, 0 },
1986 };
1987
1988 static int
1989 EncryptHelp(void)
1990 {
1991 struct encryptlist *c;
1992
1993 for (c = EncryptList; c->name; c++) {
1994 if (c->help) {
1995 if (*c->help)
1996 printf("%-15s %s\n", c->name, c->help);
1997 else
1998 printf("\n");
1999 }
2000 }
2001 return 0;
2002 }
2003
2004 static int
2005 encrypt_cmd(int argc, char *argv[])
2006 {
2007 struct encryptlist *c;
2008
2009 if (argc < 2) {
2010 fprintf(stderr,
2011 "Need an argument to 'encrypt' command. 'encrypt ?' for help.\n");
2012 return 0;
2013 }
2014
2015 c = (struct encryptlist *)
2016 genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist));
2017 if (c == 0) {
2018 fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\n",
2019 argv[1]);
2020 return 0;
2021 }
2022 if (Ambiguous((void *)c)) {
2023 fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\n",
2024 argv[1]);
2025 return 0;
2026 }
2027 argc -= 2;
2028 if (argc < c->minarg || argc > c->maxarg) {
2029 if (c->minarg == c->maxarg) {
2030 fprintf(stderr, "Need %s%d argument%s ",
2031 c->minarg < argc ? "only " : "", c->minarg,
2032 c->minarg == 1 ? "" : "s");
2033 } else {
2034 fprintf(stderr, "Need %s%d-%d arguments ",
2035 c->maxarg < argc ? "only " : "", c->minarg, c->maxarg);
2036 }
2037 fprintf(stderr, "to 'encrypt %s' command. 'encrypt ?' for help.\n",
2038 c->name);
2039 return 0;
2040 }
2041 if (c->needconnect && !connected) {
2042 if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) {
2043 printf("?Need to be connected first.\n");
2044 return 0;
2045 }
2046 }
2047 return ((*c->handler)(argc > 0 ? argv[2] : 0,
2048 argc > 1 ? argv[3] : 0));
2049 }
2050 #endif /* ENCRYPTION */
2051
2052 /*
2053 * Print status about the connection.
2054 */
2055 /*ARGSUSED*/
2056 static int
2057 status(int argc, char *argv[])
2058 {
2059 if (connected) {
2060 printf("Connected to %s.\n", hostname);
2061 if ((argc < 2) || strcmp(argv[1], "notmuch")) {
2062 int mode = getconnmode();
2063
2064 if (my_want_state_is_will(TELOPT_LINEMODE)) {
2065 printf("Operating with LINEMODE option\n");
2066 printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No");
2067 printf("%s catching of signals\n",
2068 (mode&MODE_TRAPSIG) ? "Local" : "No");
2069 slcstate();
2070 #ifdef KLUDGELINEMODE
2071 } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
2072 printf("Operating in obsolete linemode\n");
2073 #endif
2074 } else {
2075 printf("Operating in single character mode\n");
2076 if (localchars)
2077 printf("Catching signals locally\n");
2078 }
2079 printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote");
2080 if (my_want_state_is_will(TELOPT_LFLOW))
2081 printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No");
2082 #ifdef ENCRYPTION
2083 encrypt_display();
2084 #endif /* ENCRYPTION */
2085 }
2086 } else {
2087 printf("No connection.\n");
2088 }
2089 printf("Escape character is '%s'.\n", control(escape));
2090 (void) fflush(stdout);
2091 return 1;
2092 }
2093
2094 #ifdef SIGINFO
2095 /*
2096 * Function that gets called when SIGINFO is received.
2097 */
2098 void
2099 ayt_status(void)
2100 {
2101 (void) call(status, "status", "notmuch", 0);
2102 }
2103 #endif
2104
2105 static const char *
2106 sockaddr_ntop(struct sockaddr *sa)
2107 {
2108 void *addr;
2109 static char addrbuf[INET6_ADDRSTRLEN];
2110
2111 switch (sa->sa_family) {
2112 case AF_INET:
2113 addr = &((struct sockaddr_in *)sa)->sin_addr;
2114 break;
2115 case AF_UNIX:
2116 addr = &((struct sockaddr_un *)sa)->sun_path;
2117 break;
2118 #ifdef INET6
2119 case AF_INET6:
2120 addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
2121 break;
2122 #endif
2123 default:
2124 return NULL;
2125 }
2126 inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf));
2127 return addrbuf;
2128 }
2129
2130 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
2131 static int
2132 setpolicy(int lnet, struct addrinfo *res, char *policy)
2133 {
2134 char *buf;
2135 int level;
2136 int optname;
2137
2138 if (policy == NULL)
2139 return 0;
2140
2141 buf = ipsec_set_policy(policy, strlen(policy));
2142 if (buf == NULL) {
2143 printf("%s\n", ipsec_strerror());
2144 return -1;
2145 }
2146 level = res->ai_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
2147 optname = res->ai_family == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY;
2148 if (setsockopt(lnet, level, optname, buf, ipsec_get_policylen(buf)) < 0){
2149 perror("setsockopt");
2150 return -1;
2151 }
2152
2153 free(buf);
2154 return 0;
2155 }
2156 #endif
2157
2158 #ifdef INET6
2159 /*
2160 * When an Address Family related error happend, check if retry with
2161 * another AF is possible or not.
2162 * Return 1, if retry with another af is OK. Else, return 0.
2163 */
2164 static int
2165 switch_af(struct addrinfo **aip)
2166 {
2167 int nextaf;
2168 struct addrinfo *ai;
2169
2170 ai = *aip;
2171 nextaf = (ai->ai_family == AF_INET) ? AF_INET6 : AF_INET;
2172 do
2173 ai=ai->ai_next;
2174 while (ai != NULL && ai->ai_family != nextaf);
2175 *aip = ai;
2176 if (*aip != NULL) {
2177 return 1;
2178 }
2179 return 0;
2180 }
2181 #endif
2182
2183 int
2184 tn(int argc, char *argv[])
2185 {
2186 char *srp = 0;
2187 int proto = 0, opt = 0;
2188 int srlen = 0;
2189 #ifndef __APPLE__
2190 int srcroute = 0, result;
2191 #else
2192 int srcroute = 0;
2193 #endif
2194 char *cmd, *hostp = 0, *portp = 0, *user = 0;
2195 char *src_addr = NULL;
2196 struct addrinfo hints, *res, *res0 = NULL, *src_res, *src_res0 = NULL;
2197 int error = 0, af_error = 0;
2198
2199 if (connected) {
2200 printf("?Already connected to %s\n", hostname);
2201 setuid(getuid());
2202 return 0;
2203 }
2204 if (argc < 2) {
2205 (void) strcpy(line, "open ");
2206 printf("(to) ");
2207 (void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
2208 makeargv();
2209 argc = margc;
2210 argv = margv;
2211 }
2212 cmd = *argv;
2213 --argc; ++argv;
2214 while (argc) {
2215 if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?"))
2216 goto usage;
2217 if (strcmp(*argv, "-l") == 0) {
2218 --argc; ++argv;
2219 if (argc == 0)
2220 goto usage;
2221 user = *argv++;
2222 --argc;
2223 continue;
2224 }
2225 if (strcmp(*argv, "-a") == 0) {
2226 --argc; ++argv;
2227 autologin = 1;
2228 continue;
2229 }
2230 if (strcmp(*argv, "-s") == 0) {
2231 --argc; ++argv;
2232 if (argc == 0)
2233 goto usage;
2234 src_addr = *argv++;
2235 --argc;
2236 continue;
2237 }
2238 if (hostp == 0) {
2239 hostp = *argv++;
2240 --argc;
2241 continue;
2242 }
2243 if (portp == 0) {
2244 portp = *argv++;
2245 --argc;
2246 continue;
2247 }
2248 usage:
2249 printf("usage: %s [-l user] [-a] [-s src_addr] host-name [port]\n", cmd);
2250 setuid(getuid());
2251 return 0;
2252 }
2253 if (hostp == 0)
2254 goto usage;
2255
2256 if (src_addr != NULL) {
2257 memset(&hints, 0, sizeof(hints));
2258 hints.ai_flags = AI_NUMERICHOST;
2259 hints.ai_family = family;
2260 hints.ai_socktype = SOCK_STREAM;
2261 error = getaddrinfo(src_addr, 0, &hints, &src_res);
2262 #ifdef EAI_NODATA
2263 if ((error == EAI_NODATA) || (error == EAI_NONAME))
2264 #else
2265 if (error == EAI_NONAME)
2266 #endif
2267 {
2268 hints.ai_flags = 0;
2269 error = getaddrinfo(src_addr, 0, &hints, &src_res);
2270 }
2271 if (error != 0) {
2272 fprintf(stderr, "%s: %s\n", src_addr, gai_strerror(error));
2273 if (error == EAI_SYSTEM)
2274 fprintf(stderr, "%s: %s\n", src_addr, strerror(errno));
2275 setuid(getuid());
2276 return 0;
2277 }
2278 src_res0 = src_res;
2279 }
2280 if (hostp[0] == '/') {
2281 struct sockaddr_un su;
2282
2283 if (strlen(hostp) >= sizeof(su.sun_path)) {
2284 fprintf(stderr, "hostname too long for unix domain socket: %s",
2285 hostp);
2286 goto fail;
2287 }
2288 memset(&su, 0, sizeof su);
2289 su.sun_family = AF_UNIX;
2290 strncpy(su.sun_path, hostp, sizeof su.sun_path);
2291 printf("Trying %s...\n", hostp);
2292 net = socket(PF_UNIX, SOCK_STREAM, 0);
2293 if ( net < 0) {
2294 perror("socket");
2295 goto fail;
2296 }
2297 if (connect(net, (struct sockaddr *)&su, sizeof su) == -1) {
2298 perror(su.sun_path);
2299 (void) NetClose(net);
2300 goto fail;
2301 }
2302 goto af_unix;
2303 } else if (hostp[0] == '@' || hostp[0] == '!') {
2304 if (
2305 #ifdef INET6
2306 family == AF_INET6 ||
2307 #endif
2308 (hostname = strrchr(hostp, ':')) == NULL)
2309 hostname = strrchr(hostp, '@');
2310 if (hostname == NULL) {
2311 hostname = hostp;
2312 } else {
2313 hostname++;
2314 srcroute = 1;
2315 }
2316 } else
2317 hostname = hostp;
2318 if (!portp) {
2319 telnetport = 1;
2320 portp = strdup("telnet");
2321 } else if (*portp == '-') {
2322 portp++;
2323 telnetport = 1;
2324 } else if (*portp == '+') {
2325 portp++;
2326 telnetport = -1;
2327 } else
2328 telnetport = 0;
2329
2330 #ifdef __APPLE__
2331 {
2332 /*
2333 * 5760578: Attempt to convert service name to a
2334 * numeric port before calling getaddrinfo().
2335 */
2336 struct servent *srv = getservbyname(portp, NULL);
2337 if (srv != NULL) {
2338 asprintf(&portp, "%d", ntohs(srv->s_port));
2339 }
2340 }
2341 #endif /* __APPLE__ */
2342
2343 memset(&hints, 0, sizeof(hints));
2344 hints.ai_flags = AI_NUMERICHOST;
2345 hints.ai_family = family;
2346 hints.ai_socktype = SOCK_STREAM;
2347 error = getaddrinfo(hostname, portp, &hints, &res);
2348 if (error) {
2349 hints.ai_flags = AI_CANONNAME;
2350 error = getaddrinfo(hostname, portp, &hints, &res);
2351 }
2352 if (error != 0) {
2353 fprintf(stderr, "%s: %s\n", hostname, gai_strerror(error));
2354 if (error == EAI_SYSTEM)
2355 fprintf(stderr, "%s: %s\n", hostname, strerror(errno));
2356 setuid(getuid());
2357 goto fail;
2358 }
2359 if (hints.ai_flags == AI_NUMERICHOST) {
2360 /* hostname has numeric */
2361 int gni_err = 1;
2362
2363 if (doaddrlookup)
2364 gni_err = getnameinfo(res->ai_addr, res->ai_addr->sa_len,
2365 _hostname, sizeof(_hostname) - 1, NULL, 0,
2366 NI_NAMEREQD);
2367 if (gni_err != 0)
2368 (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
2369 _hostname[sizeof(_hostname)-1] = '\0';
2370 hostname = _hostname;
2371 } else {
2372 /* hostname has FQDN */
2373 if (srcroute != 0)
2374 (void) strncpy(_hostname, hostname, sizeof(_hostname) - 1);
2375 else if (res->ai_canonname != NULL)
2376 strncpy(_hostname, res->ai_canonname, sizeof(_hostname) - 1);
2377 else
2378 (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
2379 _hostname[sizeof(_hostname)-1] = '\0';
2380 hostname = _hostname;
2381 }
2382 res0 = res;
2383 #ifdef INET6
2384 af_again:
2385 #endif
2386 #ifndef __APPLE__
2387 if (srcroute != 0) {
2388 static char hostbuf[BUFSIZ];
2389
2390 if (af_error == 0) { /* save intermediate hostnames for retry */
2391 strncpy(hostbuf, hostp, BUFSIZ - 1);
2392 hostbuf[BUFSIZ - 1] = '\0';
2393 } else
2394 hostp = hostbuf;
2395 srp = 0;
2396 result = sourceroute(res, hostp, &srp, &srlen, &proto, &opt);
2397 if (result == 0) {
2398 #ifdef INET6
2399 if (family == AF_UNSPEC && af_error == 0 &&
2400 switch_af(&res) == 1) {
2401 af_error = 1;
2402 goto af_again;
2403 }
2404 #endif
2405 setuid(getuid());
2406 goto fail;
2407 } else if (result == -1) {
2408 printf("Bad source route option: %s\n", hostp);
2409 setuid(getuid());
2410 goto fail;
2411 }
2412 }
2413 #endif
2414 do {
2415 printf("Trying %s...\n", sockaddr_ntop(res->ai_addr));
2416 net = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
2417 setuid(getuid());
2418 if (net < 0) {
2419 #ifdef INET6
2420 if (family == AF_UNSPEC && af_error == 0 &&
2421 switch_af(&res) == 1) {
2422 af_error = 1;
2423 goto af_again;
2424 }
2425 #endif
2426 perror("telnet: socket");
2427 goto fail;
2428 }
2429 if (srp && setsockopt(net, proto, opt, (char *)srp, srlen) < 0)
2430 perror("setsockopt (source route)");
2431 #if defined(IPPROTO_IP) && defined(IP_TOS)
2432 if (res->ai_family == PF_INET) {
2433 # if defined(HAS_GETTOS)
2434 struct tosent *tp;
2435 if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
2436 tos = tp->t_tos;
2437 # endif
2438 if (tos < 0)
2439 tos = IPTOS_LOWDELAY;
2440 if (tos
2441 && (setsockopt(net, IPPROTO_IP, IP_TOS,
2442 (char *)&tos, sizeof(int)) < 0)
2443 && (errno != ENOPROTOOPT))
2444 perror("telnet: setsockopt (IP_TOS) (ignored)");
2445 }
2446 #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
2447
2448 if (telnet_debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
2449 perror("setsockopt (SO_DEBUG)");
2450 }
2451
2452 if (src_addr != NULL) {
2453 for (src_res = src_res0; src_res != 0; src_res = src_res->ai_next)
2454 if (src_res->ai_family == res->ai_family)
2455 break;
2456 if (src_res == NULL)
2457 src_res = src_res0;
2458 if (bind(net, src_res->ai_addr, src_res->ai_addrlen) == -1) {
2459 #ifdef INET6
2460 if (family == AF_UNSPEC && af_error == 0 &&
2461 switch_af(&res) == 1) {
2462 af_error = 1;
2463 (void) NetClose(net);
2464 goto af_again;
2465 }
2466 #endif
2467 perror("bind");
2468 (void) NetClose(net);
2469 goto fail;
2470 }
2471 }
2472 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
2473 if (setpolicy(net, res, ipsec_policy_in) < 0) {
2474 (void) NetClose(net);
2475 goto fail;
2476 }
2477 if (setpolicy(net, res, ipsec_policy_out) < 0) {
2478 (void) NetClose(net);
2479 goto fail;
2480 }
2481 #endif
2482
2483 if (connect(net, res->ai_addr, res->ai_addrlen) < 0) {
2484 struct addrinfo *next;
2485
2486 next = res->ai_next;
2487 /* If already an af failed, only try same af. */
2488 if (af_error != 0)
2489 while (next != NULL && next->ai_family != res->ai_family)
2490 next = next->ai_next;
2491 warn("connect to address %s", sockaddr_ntop(res->ai_addr));
2492 if (next != NULL) {
2493 res = next;
2494 (void) NetClose(net);
2495 continue;
2496 }
2497 warnx("Unable to connect to remote host");
2498 (void) NetClose(net);
2499 goto fail;
2500 }
2501 connected++;
2502 #ifdef AUTHENTICATION
2503 #ifdef ENCRYPTION
2504 auth_encrypt_connect(connected);
2505 #endif
2506 #endif
2507 } while (connected == 0);
2508 freeaddrinfo(res0);
2509 if (src_res0 != NULL)
2510 freeaddrinfo(src_res0);
2511 cmdrc(hostp, hostname);
2512 af_unix:
2513 connected = 1;
2514 if (autologin && user == NULL) {
2515 struct passwd *pw;
2516
2517 user = getenv("USER");
2518 if (user == NULL ||
2519 ((pw = getpwnam(user)) && pw->pw_uid != getuid())) {
2520 if ((pw = getpwuid(getuid())))
2521 user = pw->pw_name;
2522 else
2523 user = NULL;
2524 }
2525 }
2526 if (user) {
2527 env_define((unsigned char*)"USER", (unsigned char*)user);
2528 env_export((unsigned char*)"USER");
2529 }
2530 (void) call(status, "status", "notmuch", 0);
2531 if (setjmp(peerdied) == 0)
2532 telnet(user);
2533 (void) NetClose(net);
2534 ExitString("Connection closed by foreign host.\n",1);
2535 /*NOTREACHED*/
2536 fail:
2537 if (res0 != NULL)
2538 freeaddrinfo(res0);
2539 if (src_res0 != NULL)
2540 freeaddrinfo(src_res0);
2541 return 0;
2542 }
2543
2544 #define HELPINDENT (sizeof ("connect"))
2545
2546 static char
2547 openhelp[] = "connect to a site",
2548 closehelp[] = "close current connection",
2549 logouthelp[] = "forcibly logout remote user and close the connection",
2550 quithelp[] = "exit telnet",
2551 statushelp[] = "print status information",
2552 helphelp[] = "print help information",
2553 sendhelp[] = "transmit special characters ('send ?' for more)",
2554 sethelp[] = "set operating parameters ('set ?' for more)",
2555 unsethelp[] = "unset operating parameters ('unset ?' for more)",
2556 togglestring[] ="toggle operating parameters ('toggle ?' for more)",
2557 slchelp[] = "change state of special charaters ('slc ?' for more)",
2558 displayhelp[] = "display operating parameters",
2559 #ifdef AUTHENTICATION
2560 authhelp[] = "turn on (off) authentication ('auth ?' for more)",
2561 #endif
2562 #ifdef ENCRYPTION
2563 encrypthelp[] = "turn on (off) encryption ('encrypt ?' for more)",
2564 #endif /* ENCRYPTION */
2565 zhelp[] = "suspend telnet",
2566 #ifdef OPIE
2567 opiehelp[] = "compute response to OPIE challenge",
2568 #endif
2569 shellhelp[] = "invoke a subshell",
2570 envhelp[] = "change environment variables ('environ ?' for more)",
2571 modestring[] = "try to enter line or character mode ('mode ?' for more)";
2572
2573 static Command cmdtab[] = {
2574 { "close", closehelp, bye, 1 },
2575 { "logout", logouthelp, (int (*)(int, char **))logout, 1 },
2576 { "display", displayhelp, display, 0 },
2577 { "mode", modestring, modecmd, 0 },
2578 { "telnet", openhelp, tn, 0 },
2579 { "open", openhelp, tn, 0 },
2580 { "quit", quithelp, (int (*)(int, char **))quit, 0 },
2581 { "send", sendhelp, sendcmd, 0 },
2582 { "set", sethelp, setcmd, 0 },
2583 { "unset", unsethelp, unsetcmd, 0 },
2584 { "status", statushelp, status, 0 },
2585 { "toggle", togglestring, toggle, 0 },
2586 { "slc", slchelp, slccmd, 0 },
2587 #ifdef AUTHENTICATION
2588 { "auth", authhelp, auth_cmd, 0 },
2589 #endif
2590 #ifdef ENCRYPTION
2591 { "encrypt", encrypthelp, encrypt_cmd, 0 },
2592 #endif /* ENCRYPTION */
2593 { "z", zhelp, (int (*)(int, char **))suspend, 0 },
2594 { "!", shellhelp, shell, 1 },
2595 { "environ", envhelp, env_cmd, 0 },
2596 { "?", helphelp, help, 0 },
2597 #ifdef OPIE
2598 { "opie", opiehelp, opie_calc, 0 },
2599 #endif
2600 { NULL, NULL, NULL, 0 }
2601 };
2602
2603 static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead";
2604 static char escapehelp[] = "deprecated command -- use 'set escape' instead";
2605
2606 static Command cmdtab2[] = {
2607 { "help", 0, help, 0 },
2608 { "escape", escapehelp, setescape, 0 },
2609 { "crmod", crmodhelp, (int (*)(int, char **))togcrmod, 0 },
2610 { NULL, NULL, NULL, 0 }
2611 };
2612
2613
2614 /*
2615 * Call routine with argc, argv set from args (terminated by 0).
2616 */
2617
2618 static int
2619 call(intrtn_t routine, ...)
2620 {
2621 va_list ap;
2622 char *args[100];
2623 int argno = 0;
2624
2625 va_start(ap, routine);
2626 while ((args[argno++] = va_arg(ap, char *)) != 0);
2627 va_end(ap);
2628 return (*routine)(argno-1, args);
2629 }
2630
2631
2632 static Command *
2633 getcmd(char *name)
2634 {
2635 Command *cm;
2636
2637 if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))))
2638 return cm;
2639 return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
2640 }
2641
2642 void
2643 command(int top, const char *tbuf, int cnt)
2644 {
2645 Command *c;
2646
2647 setcommandmode();
2648 if (!top) {
2649 putchar('\n');
2650 } else {
2651 (void) signal(SIGINT, SIG_DFL);
2652 (void) signal(SIGQUIT, SIG_DFL);
2653 }
2654 for (;;) {
2655 if (rlogin == _POSIX_VDISABLE)
2656 printf("%s> ", prompt);
2657 if (tbuf) {
2658 char *cp;
2659 cp = line;
2660 while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
2661 cnt--;
2662 tbuf = 0;
2663 if (cp == line || *--cp != '\n' || cp == line)
2664 goto getline;
2665 *cp = '\0';
2666 if (rlogin == _POSIX_VDISABLE)
2667 printf("%s\n", line);
2668 } else {
2669 getline:
2670 if (rlogin != _POSIX_VDISABLE)
2671 printf("%s> ", prompt);
2672 if (fgets(line, sizeof(line), stdin) == NULL) {
2673 if (feof(stdin) || ferror(stdin)) {
2674 (void) quit();
2675 /*NOTREACHED*/
2676 }
2677 break;
2678 }
2679 }
2680 if (line[0] == 0)
2681 break;
2682 makeargv();
2683 if (margv[0] == 0) {
2684 break;
2685 }
2686 c = getcmd(margv[0]);
2687 if (Ambiguous((void *)c)) {
2688 printf("?Ambiguous command\n");
2689 continue;
2690 }
2691 if (c == 0) {
2692 printf("?Invalid command\n");
2693 continue;
2694 }
2695 if (c->needconnect && !connected) {
2696 printf("?Need to be connected first.\n");
2697 continue;
2698 }
2699 if ((*c->handler)(margc, margv)) {
2700 break;
2701 }
2702 }
2703 if (!top) {
2704 if (!connected) {
2705 longjmp(toplevel, 1);
2706 /*NOTREACHED*/
2707 }
2708 setconnmode(0);
2709 }
2710 }
2711 \f
2712 /*
2713 * Help command.
2714 */
2715 static int
2716 help(int argc, char *argv[])
2717 {
2718 Command *c;
2719
2720 if (argc == 1) {
2721 printf("Commands may be abbreviated. Commands are:\n\n");
2722 for (c = cmdtab; c->name; c++)
2723 if (c->help) {
2724 printf("%-*s\t%s\n", (int)HELPINDENT, c->name,
2725 c->help);
2726 }
2727 return 0;
2728 }
2729 else while (--argc > 0) {
2730 char *arg;
2731 arg = *++argv;
2732 c = getcmd(arg);
2733 if (Ambiguous((void *)c))
2734 printf("?Ambiguous help command %s\n", arg);
2735 else if (c == (Command *)0)
2736 printf("?Invalid help command %s\n", arg);
2737 else
2738 printf("%s\n", c->help);
2739 }
2740 return 0;
2741 }
2742
2743 static char *rcname = 0;
2744 static char rcbuf[128];
2745
2746 void
2747 cmdrc(char *m1, char *m2)
2748 {
2749 Command *c;
2750 FILE *rcfile;
2751 int gotmachine = 0;
2752 int l1 = strlen(m1);
2753 int l2 = strlen(m2);
2754 char m1save[MAXHOSTNAMELEN];
2755
2756 if (skiprc)
2757 return;
2758
2759 strlcpy(m1save, m1, sizeof(m1save));
2760 m1 = m1save;
2761
2762 if (rcname == 0) {
2763 rcname = getenv("HOME");
2764 if (rcname && (strlen(rcname) + 10) < sizeof(rcbuf))
2765 strcpy(rcbuf, rcname);
2766 else
2767 rcbuf[0] = '\0';
2768 strcat(rcbuf, "/.telnetrc");
2769 rcname = rcbuf;
2770 }
2771
2772 if ((rcfile = fopen(rcname, "r")) == 0) {
2773 return;
2774 }
2775
2776 for (;;) {
2777 if (fgets(line, sizeof(line), rcfile) == NULL)
2778 break;
2779 if (line[0] == 0)
2780 break;
2781 if (line[0] == '#')
2782 continue;
2783 if (gotmachine) {
2784 if (!isspace(line[0]))
2785 gotmachine = 0;
2786 }
2787 if (gotmachine == 0) {
2788 if (isspace(line[0]))
2789 continue;
2790 if (strncasecmp(line, m1, l1) == 0)
2791 strncpy(line, &line[l1], sizeof(line) - l1);
2792 else if (strncasecmp(line, m2, l2) == 0)
2793 strncpy(line, &line[l2], sizeof(line) - l2);
2794 else if (strncasecmp(line, "DEFAULT", 7) == 0)
2795 strncpy(line, &line[7], sizeof(line) - 7);
2796 else
2797 continue;
2798 if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
2799 continue;
2800 gotmachine = 1;
2801 }
2802 makeargv();
2803 if (margv[0] == 0)
2804 continue;
2805 c = getcmd(margv[0]);
2806 if (Ambiguous((void *)c)) {
2807 printf("?Ambiguous command: %s\n", margv[0]);
2808 continue;
2809 }
2810 if (c == 0) {
2811 printf("?Invalid command: %s\n", margv[0]);
2812 continue;
2813 }
2814 /*
2815 * This should never happen...
2816 */
2817 if (c->needconnect && !connected) {
2818 printf("?Need to be connected first for %s.\n", margv[0]);
2819 continue;
2820 }
2821 (*c->handler)(margc, margv);
2822 }
2823 fclose(rcfile);
2824 }
2825
2826 #ifndef __APPLE__
2827 /*
2828 * Source route is handed in as
2829 * [!]@hop1@hop2...[@|:]dst
2830 * If the leading ! is present, it is a
2831 * strict source route, otherwise it is
2832 * assmed to be a loose source route.
2833 *
2834 * We fill in the source route option as
2835 * hop1,hop2,hop3...dest
2836 * and return a pointer to hop1, which will
2837 * be the address to connect() to.
2838 *
2839 * Arguments:
2840 *
2841 * res: ponter to addrinfo structure which contains sockaddr to
2842 * the host to connect to.
2843 *
2844 * arg: pointer to route list to decipher
2845 *
2846 * cpp: If *cpp is not equal to NULL, this is a
2847 * pointer to a pointer to a character array
2848 * that should be filled in with the option.
2849 *
2850 * lenp: pointer to an integer that contains the
2851 * length of *cpp if *cpp != NULL.
2852 *
2853 * protop: pointer to an integer that should be filled in with
2854 * appropriate protocol for setsockopt, as socket
2855 * protocol family.
2856 *
2857 * optp: pointer to an integer that should be filled in with
2858 * appropriate option for setsockopt, as socket protocol
2859 * family.
2860 *
2861 * Return values:
2862 *
2863 * If the return value is 1, then all operations are
2864 * successful. If the
2865 * return value is -1, there was a syntax error in the
2866 * option, either unknown characters, or too many hosts.
2867 * If the return value is 0, one of the hostnames in the
2868 * path is unknown, and *cpp is set to point to the bad
2869 * hostname.
2870 *
2871 * *cpp: If *cpp was equal to NULL, it will be filled
2872 * in with a pointer to our static area that has
2873 * the option filled in. This will be 32bit aligned.
2874 *
2875 * *lenp: This will be filled in with how long the option
2876 * pointed to by *cpp is.
2877 *
2878 * *protop: This will be filled in with appropriate protocol for
2879 * setsockopt, as socket protocol family.
2880 *
2881 * *optp: This will be filled in with appropriate option for
2882 * setsockopt, as socket protocol family.
2883 */
2884 static int
2885 sourceroute(struct addrinfo *ai, char *arg, char **cpp, int *lenp, int *protop, int *optp)
2886 {
2887 static char buf[1024 + ALIGNBYTES]; /*XXX*/
2888 char *cp, *cp2, *lsrp, *ep;
2889 struct sockaddr_in *_sin;
2890 #ifdef INET6
2891 struct sockaddr_in6 *sin6;
2892 struct cmsghdr *cmsg = NULL;
2893 #endif
2894 struct addrinfo hints, *res;
2895 int error;
2896 char c;
2897
2898 /*
2899 * Verify the arguments, and make sure we have
2900 * at least 7 bytes for the option.
2901 */
2902 if (cpp == NULL || lenp == NULL)
2903 return -1;
2904 if (*cpp != NULL) {
2905 switch (ai->ai_family) {
2906 case AF_INET:
2907 if (*lenp < 7)
2908 return -1;
2909 break;
2910 #ifdef INET6
2911 case AF_INET6:
2912 if (*lenp < (int)CMSG_SPACE(sizeof(struct ip6_rthdr) +
2913 sizeof(struct in6_addr)))
2914 return -1;
2915 break;
2916 #endif
2917 }
2918 }
2919 /*
2920 * Decide whether we have a buffer passed to us,
2921 * or if we need to use our own static buffer.
2922 */
2923 if (*cpp) {
2924 lsrp = *cpp;
2925 ep = lsrp + *lenp;
2926 } else {
2927 *cpp = lsrp = (char *)ALIGN(buf);
2928 ep = lsrp + 1024;
2929 }
2930
2931 cp = arg;
2932
2933 #ifdef INET6
2934 if (ai->ai_family == AF_INET6) {
2935 cmsg = inet6_rthdr_init(*cpp, IPV6_RTHDR_TYPE_0);
2936 if (*cp != '@')
2937 return -1;
2938 *protop = IPPROTO_IPV6;
2939 *optp = IPV6_PKTOPTIONS;
2940 } else
2941 #endif
2942 {
2943 /*
2944 * Next, decide whether we have a loose source
2945 * route or a strict source route, and fill in
2946 * the begining of the option.
2947 */
2948 if (*cp == '!') {
2949 cp++;
2950 *lsrp++ = IPOPT_SSRR;
2951 } else
2952 *lsrp++ = IPOPT_LSRR;
2953
2954 if (*cp != '@')
2955 return -1;
2956
2957 lsrp++; /* skip over length, we'll fill it in later */
2958 *lsrp++ = 4;
2959 *protop = IPPROTO_IP;
2960 *optp = IP_OPTIONS;
2961 }
2962
2963 cp++;
2964 memset(&hints, 0, sizeof(hints));
2965 hints.ai_family = ai->ai_family;
2966 hints.ai_socktype = SOCK_STREAM;
2967 for (c = 0;;) {
2968 if (
2969 #ifdef INET6
2970 ai->ai_family != AF_INET6 &&
2971 #endif
2972 c == ':')
2973 cp2 = 0;
2974 else for (cp2 = cp; (c = *cp2); cp2++) {
2975 if (c == ',') {
2976 *cp2++ = '\0';
2977 if (*cp2 == '@')
2978 cp2++;
2979 } else if (c == '@') {
2980 *cp2++ = '\0';
2981 } else if (
2982 #ifdef INET6
2983 ai->ai_family != AF_INET6 &&
2984 #endif
2985 c == ':') {
2986 *cp2++ = '\0';
2987 } else
2988 continue;
2989 break;
2990 }
2991 if (!c)
2992 cp2 = 0;
2993
2994 hints.ai_flags = AI_NUMERICHOST;
2995 error = getaddrinfo(cp, NULL, &hints, &res);
2996 #ifdef EAI_NODATA
2997 if ((error == EAI_NODATA) || (error == EAI_NONAME))
2998 #else
2999 if (error == EAI_NONAME)
3000 #endif
3001 {
3002 hints.ai_flags = 0;
3003 error = getaddrinfo(cp, NULL, &hints, &res);
3004 }
3005 if (error != 0) {
3006 fprintf(stderr, "%s: %s\n", cp, gai_strerror(error));
3007 if (error == EAI_SYSTEM)
3008 fprintf(stderr, "%s: %s\n", cp,
3009 strerror(errno));
3010 *cpp = cp;
3011 return(0);
3012 }
3013 #ifdef INET6
3014 if (res->ai_family == AF_INET6) {
3015 sin6 = (struct sockaddr_in6 *)res->ai_addr;
3016 inet6_rthdr_add(cmsg, &sin6->sin6_addr,
3017 IPV6_RTHDR_LOOSE);
3018 } else
3019 #endif
3020 {
3021 _sin = (struct sockaddr_in *)res->ai_addr;
3022 memcpy(lsrp, (char *)&_sin->sin_addr, 4);
3023 lsrp += 4;
3024 }
3025 if (cp2)
3026 cp = cp2;
3027 else
3028 break;
3029 /*
3030 * Check to make sure there is space for next address
3031 */
3032 #ifdef INET6
3033 if (res->ai_family == AF_INET6) {
3034 if (((char *)CMSG_DATA(cmsg) +
3035 sizeof(struct ip6_rthdr) +
3036 ((inet6_rthdr_segments(cmsg) + 1) *
3037 sizeof(struct in6_addr))) > ep)
3038 return -1;
3039 } else
3040 #endif
3041 if (lsrp + 4 > ep)
3042 return -1;
3043 freeaddrinfo(res);
3044 }
3045 #ifdef INET6
3046 if (res->ai_family == AF_INET6) {
3047 inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE);
3048 *lenp = cmsg->cmsg_len;
3049 } else
3050 #endif
3051 {
3052 if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
3053 *cpp = 0;
3054 *lenp = 0;
3055 return -1;
3056 }
3057 *lsrp++ = IPOPT_NOP; /* 32 bit word align it */
3058 *lenp = lsrp - *cpp;
3059 }
3060 freeaddrinfo(res);
3061 return 1;
3062 }
3063 #endif