1*3aaa63ebSderaadt /* $OpenBSD: command.c,v 1.18 2019/06/28 13:35:00 deraadt Exp $ */
2f391cec5Snicm
3f391cec5Snicm /*
4f391cec5Snicm * Copyright (c) 2012 Nicholas Marriott <nicm@openbsd.org>
5f391cec5Snicm *
6f391cec5Snicm * Permission to use, copy, modify, and distribute this software for any
7f391cec5Snicm * purpose with or without fee is hereby granted, provided that the above
8f391cec5Snicm * copyright notice and this permission notice appear in all copies.
9f391cec5Snicm *
10f391cec5Snicm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11f391cec5Snicm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12f391cec5Snicm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13f391cec5Snicm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14f391cec5Snicm * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15f391cec5Snicm * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16f391cec5Snicm * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17f391cec5Snicm */
18f391cec5Snicm
19f391cec5Snicm #include <sys/types.h>
20f391cec5Snicm #include <sys/ioctl.h>
21f391cec5Snicm #include <sys/wait.h>
22f391cec5Snicm
23f391cec5Snicm #include <event.h>
24f391cec5Snicm #include <errno.h>
25f391cec5Snicm #include <fcntl.h>
26a3cadbf3Snicm #include <limits.h>
27f391cec5Snicm #include <paths.h>
28f391cec5Snicm #include <signal.h>
29f391cec5Snicm #include <stdlib.h>
30f391cec5Snicm #include <stdio.h>
31087a5e3bSderaadt #include <string.h>
32f391cec5Snicm #include <unistd.h>
33f3767adaSnicm #include <vis.h>
34f391cec5Snicm
35f391cec5Snicm #include "cu.h"
36f391cec5Snicm
37f391cec5Snicm void pipe_command(void);
382001eabaSnicm void connect_command(void);
39f391cec5Snicm void send_file(void);
40649fc061Snicm void send_xmodem(void);
4143a6699fSderaadt void set_speed(void);
4243a6699fSderaadt void start_record(void);
43f391cec5Snicm
44f391cec5Snicm void
pipe_command(void)45f391cec5Snicm pipe_command(void)
46f391cec5Snicm {
47f391cec5Snicm const char *cmd;
48f391cec5Snicm pid_t pid;
49f391cec5Snicm int fd;
50f391cec5Snicm
51f391cec5Snicm cmd = get_input("Local command?");
52f391cec5Snicm if (cmd == NULL || *cmd == '\0')
53f391cec5Snicm return;
54f391cec5Snicm
55ca5f2657Snicm restore_termios();
56668574b2Snicm set_blocking(line_fd, 1);
57ca5f2657Snicm
58f391cec5Snicm switch (pid = fork()) {
59f391cec5Snicm case -1:
6011403328Snicm cu_err(1, "fork");
61f391cec5Snicm case 0:
62f391cec5Snicm fd = open(_PATH_DEVNULL, O_RDWR);
63*3aaa63ebSderaadt if (fd == -1 || dup2(fd, STDIN_FILENO) == -1)
64f391cec5Snicm _exit(1);
65f391cec5Snicm close(fd);
66f391cec5Snicm
67ca5f2657Snicm if (signal(SIGINT, SIG_DFL) == SIG_ERR)
68ca5f2657Snicm _exit(1);
69ca5f2657Snicm if (signal(SIGQUIT, SIG_DFL) == SIG_ERR)
70ca5f2657Snicm _exit(1);
71ca5f2657Snicm
72f391cec5Snicm /* attach stdout to line */
73f391cec5Snicm if (dup2(line_fd, STDOUT_FILENO) == -1)
74f391cec5Snicm _exit(1);
75f391cec5Snicm
76d8a7f187Snicm if (closefrom(STDERR_FILENO + 1) != 0)
77f391cec5Snicm _exit(1);
78f391cec5Snicm
79b6d7cb74Snicm execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL);
80f391cec5Snicm _exit(1);
81f391cec5Snicm default:
82f391cec5Snicm while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
83f391cec5Snicm /* nothing */;
84f391cec5Snicm break;
85f391cec5Snicm }
86ca5f2657Snicm
87668574b2Snicm set_blocking(line_fd, 0);
88ca5f2657Snicm set_termios();
89f391cec5Snicm }
90f391cec5Snicm
91f391cec5Snicm void
connect_command(void)922001eabaSnicm connect_command(void)
932001eabaSnicm {
942001eabaSnicm const char *cmd;
952001eabaSnicm pid_t pid;
962001eabaSnicm
972001eabaSnicm /*
982001eabaSnicm * Fork a program with:
992001eabaSnicm * 0 <-> remote tty in
1002001eabaSnicm * 1 <-> remote tty out
1012001eabaSnicm * 2 <-> local tty stderr
1022001eabaSnicm */
1032001eabaSnicm
1042001eabaSnicm cmd = get_input("Local command?");
1052001eabaSnicm if (cmd == NULL || *cmd == '\0')
1062001eabaSnicm return;
1072001eabaSnicm
1082001eabaSnicm restore_termios();
109668574b2Snicm set_blocking(line_fd, 1);
1102001eabaSnicm
1112001eabaSnicm switch (pid = fork()) {
1122001eabaSnicm case -1:
11311403328Snicm cu_err(1, "fork");
1142001eabaSnicm case 0:
1152001eabaSnicm if (signal(SIGINT, SIG_DFL) == SIG_ERR)
1162001eabaSnicm _exit(1);
1172001eabaSnicm if (signal(SIGQUIT, SIG_DFL) == SIG_ERR)
1182001eabaSnicm _exit(1);
1192001eabaSnicm
1202001eabaSnicm /* attach stdout and stdin to line */
1212001eabaSnicm if (dup2(line_fd, STDOUT_FILENO) == -1)
1222001eabaSnicm _exit(1);
1232001eabaSnicm if (dup2(line_fd, STDIN_FILENO) == -1)
1242001eabaSnicm _exit(1);
1252001eabaSnicm
126d8a7f187Snicm if (closefrom(STDERR_FILENO + 1) != 0)
1272001eabaSnicm _exit(1);
1282001eabaSnicm
129b6d7cb74Snicm execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL);
1302001eabaSnicm _exit(1);
1312001eabaSnicm default:
1322001eabaSnicm while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
1332001eabaSnicm /* nothing */;
1342001eabaSnicm break;
1352001eabaSnicm }
1362001eabaSnicm
137668574b2Snicm set_blocking(line_fd, 0);
1382001eabaSnicm set_termios();
1392001eabaSnicm }
1402001eabaSnicm
1412001eabaSnicm void
send_file(void)142f391cec5Snicm send_file(void)
143f391cec5Snicm {
144f391cec5Snicm const char *file;
145f391cec5Snicm FILE *f;
146f391cec5Snicm char buf[BUFSIZ], *expanded;
147f391cec5Snicm size_t len;
148f391cec5Snicm
149f391cec5Snicm file = get_input("Local file?");
150f391cec5Snicm if (file == NULL || *file == '\0')
151f391cec5Snicm return;
152f391cec5Snicm
153f391cec5Snicm expanded = tilde_expand(file);
154f391cec5Snicm f = fopen(expanded, "r");
155f391cec5Snicm if (f == NULL) {
15611403328Snicm cu_warn("%s", file);
157f391cec5Snicm return;
158f391cec5Snicm }
159f391cec5Snicm
160f391cec5Snicm while (!feof(f) && !ferror(f)) {
161f391cec5Snicm len = fread(buf, 1, sizeof(buf), f);
162f391cec5Snicm if (len != 0)
163f391cec5Snicm bufferevent_write(line_ev, buf, len);
164f391cec5Snicm }
165f391cec5Snicm
166f391cec5Snicm fclose(f);
167f391cec5Snicm free(expanded);
168f391cec5Snicm }
169f391cec5Snicm
170f391cec5Snicm void
send_xmodem(void)171649fc061Snicm send_xmodem(void)
172649fc061Snicm {
173649fc061Snicm const char *file;
174649fc061Snicm char *expanded;
175649fc061Snicm
176649fc061Snicm file = get_input("Local file?");
177649fc061Snicm if (file == NULL || *file == '\0')
178649fc061Snicm return;
179649fc061Snicm
180649fc061Snicm expanded = tilde_expand(file);
181649fc061Snicm xmodem_send(expanded);
182649fc061Snicm free(expanded);
183649fc061Snicm }
184649fc061Snicm
185649fc061Snicm void
set_speed(void)186909d4fcfSnicm set_speed(void)
187909d4fcfSnicm {
188909d4fcfSnicm const char *s, *errstr;
189909d4fcfSnicm int speed;
190909d4fcfSnicm
191909d4fcfSnicm s = get_input("New speed?");
192909d4fcfSnicm if (s == NULL || *s == '\0')
193909d4fcfSnicm return;
194909d4fcfSnicm
195909d4fcfSnicm speed = strtonum(s, 0, UINT_MAX, &errstr);
196909d4fcfSnicm if (errstr != NULL) {
19711403328Snicm cu_warnx("speed is %s: %s", errstr, s);
198909d4fcfSnicm return;
199909d4fcfSnicm }
200909d4fcfSnicm
20111403328Snicm if (set_line(speed) != 0)
20211403328Snicm cu_warn("tcsetattr");
203909d4fcfSnicm }
204909d4fcfSnicm
205909d4fcfSnicm void
start_record(void)20666d5e211Snicm start_record(void)
20766d5e211Snicm {
20866d5e211Snicm const char *file;
20966d5e211Snicm
21066d5e211Snicm if (record_file != NULL) {
21166d5e211Snicm fclose(record_file);
21266d5e211Snicm record_file = NULL;
21366d5e211Snicm }
21466d5e211Snicm
21566d5e211Snicm file = get_input("Record file?");
21666d5e211Snicm if (file == NULL || *file == '\0')
21766d5e211Snicm return;
21866d5e211Snicm
21966d5e211Snicm record_file = fopen(file, "a");
22066d5e211Snicm if (record_file == NULL)
22166d5e211Snicm cu_warnx("%s", file);
22266d5e211Snicm }
22366d5e211Snicm
22466d5e211Snicm void
do_command(char c)225f391cec5Snicm do_command(char c)
226f391cec5Snicm {
227f3767adaSnicm char esc[4 + 1];
228f3767adaSnicm
229087a5e3bSderaadt if (restricted && strchr("CRX$>", c) != NULL) {
230087a5e3bSderaadt cu_warnx("~%c command is not allowed in restricted mode", c);
231087a5e3bSderaadt return;
232087a5e3bSderaadt }
233087a5e3bSderaadt
234f391cec5Snicm switch (c) {
235f391cec5Snicm case '.':
236f391cec5Snicm case '\004': /* ^D */
237f391cec5Snicm event_loopexit(NULL);
238f391cec5Snicm break;
239f391cec5Snicm case '\032': /* ^Z */
240f391cec5Snicm restore_termios();
241f391cec5Snicm kill(getpid(), SIGTSTP);
242f391cec5Snicm set_termios();
243f391cec5Snicm break;
2442001eabaSnicm case 'C':
2452001eabaSnicm connect_command();
2462001eabaSnicm break;
247beec8f30Snicm case 'D':
248beec8f30Snicm ioctl(line_fd, TIOCCDTR, NULL);
249beec8f30Snicm sleep(1);
250beec8f30Snicm ioctl(line_fd, TIOCSDTR, NULL);
251beec8f30Snicm break;
25266d5e211Snicm case 'R':
25366d5e211Snicm start_record();
25466d5e211Snicm break;
255909d4fcfSnicm case 'S':
256909d4fcfSnicm set_speed();
257909d4fcfSnicm break;
258649fc061Snicm case 'X':
259649fc061Snicm send_xmodem();
260649fc061Snicm break;
261f391cec5Snicm case '$':
262f391cec5Snicm pipe_command();
263f391cec5Snicm break;
264f391cec5Snicm case '>':
265f391cec5Snicm send_file();
266f391cec5Snicm break;
267f391cec5Snicm case '#':
268f391cec5Snicm ioctl(line_fd, TIOCSBRK, NULL);
269f391cec5Snicm sleep(1);
270f391cec5Snicm ioctl(line_fd, TIOCCBRK, NULL);
271f391cec5Snicm break;
272f3767adaSnicm default:
273f3767adaSnicm if ((u_char)c == escape_char)
274f3767adaSnicm bufferevent_write(line_ev, &c, 1);
27555e67042Snicm break;
276f391cec5Snicm case '?':
277f3767adaSnicm vis(esc, escape_char, VIS_WHITE | VIS_NOSLASH, 0);
278f391cec5Snicm printf("\r\n"
279f3767adaSnicm "%s# send break\r\n"
280f3767adaSnicm "%s$ pipe local command to remote host\r\n"
281f3767adaSnicm "%s> send file to remote host\r\n"
282f3767adaSnicm "%sC connect program to remote host\r\n"
283f3767adaSnicm "%sD de-assert DTR line briefly\r\n"
284f3767adaSnicm "%sR start recording to file\r\n"
285f3767adaSnicm "%sS set speed\r\n"
286f3767adaSnicm "%sX send file with XMODEM\r\n"
287f3767adaSnicm "%s? get this summary\r\n",
288f3767adaSnicm esc, esc, esc, esc, esc, esc, esc, esc, esc
289909d4fcfSnicm );
290f391cec5Snicm break;
291f391cec5Snicm }
292f391cec5Snicm }
293