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