1 /* $OpenBSD: command.c,v 1.18 2019/06/28 13:35:00 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2012 Nicholas Marriott <nicm@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/ioctl.h> 21 #include <sys/wait.h> 22 23 #include <event.h> 24 #include <errno.h> 25 #include <fcntl.h> 26 #include <limits.h> 27 #include <paths.h> 28 #include <signal.h> 29 #include <stdlib.h> 30 #include <stdio.h> 31 #include <string.h> 32 #include <unistd.h> 33 #include <vis.h> 34 35 #include "cu.h" 36 37 void pipe_command(void); 38 void connect_command(void); 39 void send_file(void); 40 void send_xmodem(void); 41 void set_speed(void); 42 void start_record(void); 43 44 void 45 pipe_command(void) 46 { 47 const char *cmd; 48 pid_t pid; 49 int fd; 50 51 cmd = get_input("Local command?"); 52 if (cmd == NULL || *cmd == '\0') 53 return; 54 55 restore_termios(); 56 set_blocking(line_fd, 1); 57 58 switch (pid = fork()) { 59 case -1: 60 cu_err(1, "fork"); 61 case 0: 62 fd = open(_PATH_DEVNULL, O_RDWR); 63 if (fd == -1 || dup2(fd, STDIN_FILENO) == -1) 64 _exit(1); 65 close(fd); 66 67 if (signal(SIGINT, SIG_DFL) == SIG_ERR) 68 _exit(1); 69 if (signal(SIGQUIT, SIG_DFL) == SIG_ERR) 70 _exit(1); 71 72 /* attach stdout to line */ 73 if (dup2(line_fd, STDOUT_FILENO) == -1) 74 _exit(1); 75 76 if (closefrom(STDERR_FILENO + 1) != 0) 77 _exit(1); 78 79 execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL); 80 _exit(1); 81 default: 82 while (waitpid(pid, NULL, 0) == -1 && errno == EINTR) 83 /* nothing */; 84 break; 85 } 86 87 set_blocking(line_fd, 0); 88 set_termios(); 89 } 90 91 void 92 connect_command(void) 93 { 94 const char *cmd; 95 pid_t pid; 96 97 /* 98 * Fork a program with: 99 * 0 <-> remote tty in 100 * 1 <-> remote tty out 101 * 2 <-> local tty stderr 102 */ 103 104 cmd = get_input("Local command?"); 105 if (cmd == NULL || *cmd == '\0') 106 return; 107 108 restore_termios(); 109 set_blocking(line_fd, 1); 110 111 switch (pid = fork()) { 112 case -1: 113 cu_err(1, "fork"); 114 case 0: 115 if (signal(SIGINT, SIG_DFL) == SIG_ERR) 116 _exit(1); 117 if (signal(SIGQUIT, SIG_DFL) == SIG_ERR) 118 _exit(1); 119 120 /* attach stdout and stdin to line */ 121 if (dup2(line_fd, STDOUT_FILENO) == -1) 122 _exit(1); 123 if (dup2(line_fd, STDIN_FILENO) == -1) 124 _exit(1); 125 126 if (closefrom(STDERR_FILENO + 1) != 0) 127 _exit(1); 128 129 execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL); 130 _exit(1); 131 default: 132 while (waitpid(pid, NULL, 0) == -1 && errno == EINTR) 133 /* nothing */; 134 break; 135 } 136 137 set_blocking(line_fd, 0); 138 set_termios(); 139 } 140 141 void 142 send_file(void) 143 { 144 const char *file; 145 FILE *f; 146 char buf[BUFSIZ], *expanded; 147 size_t len; 148 149 file = get_input("Local file?"); 150 if (file == NULL || *file == '\0') 151 return; 152 153 expanded = tilde_expand(file); 154 f = fopen(expanded, "r"); 155 if (f == NULL) { 156 cu_warn("%s", file); 157 return; 158 } 159 160 while (!feof(f) && !ferror(f)) { 161 len = fread(buf, 1, sizeof(buf), f); 162 if (len != 0) 163 bufferevent_write(line_ev, buf, len); 164 } 165 166 fclose(f); 167 free(expanded); 168 } 169 170 void 171 send_xmodem(void) 172 { 173 const char *file; 174 char *expanded; 175 176 file = get_input("Local file?"); 177 if (file == NULL || *file == '\0') 178 return; 179 180 expanded = tilde_expand(file); 181 xmodem_send(expanded); 182 free(expanded); 183 } 184 185 void 186 set_speed(void) 187 { 188 const char *s, *errstr; 189 int speed; 190 191 s = get_input("New speed?"); 192 if (s == NULL || *s == '\0') 193 return; 194 195 speed = strtonum(s, 0, UINT_MAX, &errstr); 196 if (errstr != NULL) { 197 cu_warnx("speed is %s: %s", errstr, s); 198 return; 199 } 200 201 if (set_line(speed) != 0) 202 cu_warn("tcsetattr"); 203 } 204 205 void 206 start_record(void) 207 { 208 const char *file; 209 210 if (record_file != NULL) { 211 fclose(record_file); 212 record_file = NULL; 213 } 214 215 file = get_input("Record file?"); 216 if (file == NULL || *file == '\0') 217 return; 218 219 record_file = fopen(file, "a"); 220 if (record_file == NULL) 221 cu_warnx("%s", file); 222 } 223 224 void 225 do_command(char c) 226 { 227 char esc[4 + 1]; 228 229 if (restricted && strchr("CRX$>", c) != NULL) { 230 cu_warnx("~%c command is not allowed in restricted mode", c); 231 return; 232 } 233 234 switch (c) { 235 case '.': 236 case '\004': /* ^D */ 237 event_loopexit(NULL); 238 break; 239 case '\032': /* ^Z */ 240 restore_termios(); 241 kill(getpid(), SIGTSTP); 242 set_termios(); 243 break; 244 case 'C': 245 connect_command(); 246 break; 247 case 'D': 248 ioctl(line_fd, TIOCCDTR, NULL); 249 sleep(1); 250 ioctl(line_fd, TIOCSDTR, NULL); 251 break; 252 case 'R': 253 start_record(); 254 break; 255 case 'S': 256 set_speed(); 257 break; 258 case 'X': 259 send_xmodem(); 260 break; 261 case '$': 262 pipe_command(); 263 break; 264 case '>': 265 send_file(); 266 break; 267 case '#': 268 ioctl(line_fd, TIOCSBRK, NULL); 269 sleep(1); 270 ioctl(line_fd, TIOCCBRK, NULL); 271 break; 272 default: 273 if ((u_char)c == escape_char) 274 bufferevent_write(line_ev, &c, 1); 275 break; 276 case '?': 277 vis(esc, escape_char, VIS_WHITE | VIS_NOSLASH, 0); 278 printf("\r\n" 279 "%s# send break\r\n" 280 "%s$ pipe local command to remote host\r\n" 281 "%s> send file to remote host\r\n" 282 "%sC connect program to remote host\r\n" 283 "%sD de-assert DTR line briefly\r\n" 284 "%sR start recording to file\r\n" 285 "%sS set speed\r\n" 286 "%sX send file with XMODEM\r\n" 287 "%s? get this summary\r\n", 288 esc, esc, esc, esc, esc, esc, esc, esc, esc 289 ); 290 break; 291 } 292 } 293