1 /* $OpenBSD: command.c,v 1.16 2017/12/10 01:03:46 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 34 #include "cu.h" 35 36 void pipe_command(void); 37 void connect_command(void); 38 void send_file(void); 39 void send_xmodem(void); 40 void set_speed(void); 41 void start_record(void); 42 43 void 44 pipe_command(void) 45 { 46 const char *cmd; 47 pid_t pid; 48 int fd; 49 50 cmd = get_input("Local command?"); 51 if (cmd == NULL || *cmd == '\0') 52 return; 53 54 restore_termios(); 55 set_blocking(line_fd, 1); 56 57 switch (pid = fork()) { 58 case -1: 59 cu_err(1, "fork"); 60 case 0: 61 fd = open(_PATH_DEVNULL, O_RDWR); 62 if (fd < 0 || dup2(fd, STDIN_FILENO) == -1) 63 _exit(1); 64 close(fd); 65 66 if (signal(SIGINT, SIG_DFL) == SIG_ERR) 67 _exit(1); 68 if (signal(SIGQUIT, SIG_DFL) == SIG_ERR) 69 _exit(1); 70 71 /* attach stdout to line */ 72 if (dup2(line_fd, STDOUT_FILENO) == -1) 73 _exit(1); 74 75 if (closefrom(STDERR_FILENO + 1) != 0) 76 _exit(1); 77 78 execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL); 79 _exit(1); 80 default: 81 while (waitpid(pid, NULL, 0) == -1 && errno == EINTR) 82 /* nothing */; 83 break; 84 } 85 86 set_blocking(line_fd, 0); 87 set_termios(); 88 } 89 90 void 91 connect_command(void) 92 { 93 const char *cmd; 94 pid_t pid; 95 96 /* 97 * Fork a program with: 98 * 0 <-> remote tty in 99 * 1 <-> remote tty out 100 * 2 <-> local tty stderr 101 */ 102 103 cmd = get_input("Local command?"); 104 if (cmd == NULL || *cmd == '\0') 105 return; 106 107 restore_termios(); 108 set_blocking(line_fd, 1); 109 110 switch (pid = fork()) { 111 case -1: 112 cu_err(1, "fork"); 113 case 0: 114 if (signal(SIGINT, SIG_DFL) == SIG_ERR) 115 _exit(1); 116 if (signal(SIGQUIT, SIG_DFL) == SIG_ERR) 117 _exit(1); 118 119 /* attach stdout and stdin to line */ 120 if (dup2(line_fd, STDOUT_FILENO) == -1) 121 _exit(1); 122 if (dup2(line_fd, STDIN_FILENO) == -1) 123 _exit(1); 124 125 if (closefrom(STDERR_FILENO + 1) != 0) 126 _exit(1); 127 128 execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL); 129 _exit(1); 130 default: 131 while (waitpid(pid, NULL, 0) == -1 && errno == EINTR) 132 /* nothing */; 133 break; 134 } 135 136 set_blocking(line_fd, 0); 137 set_termios(); 138 } 139 140 void 141 send_file(void) 142 { 143 const char *file; 144 FILE *f; 145 char buf[BUFSIZ], *expanded; 146 size_t len; 147 148 file = get_input("Local file?"); 149 if (file == NULL || *file == '\0') 150 return; 151 152 expanded = tilde_expand(file); 153 f = fopen(expanded, "r"); 154 if (f == NULL) { 155 cu_warn("%s", file); 156 return; 157 } 158 159 while (!feof(f) && !ferror(f)) { 160 len = fread(buf, 1, sizeof(buf), f); 161 if (len != 0) 162 bufferevent_write(line_ev, buf, len); 163 } 164 165 fclose(f); 166 free(expanded); 167 } 168 169 void 170 send_xmodem(void) 171 { 172 const char *file; 173 char *expanded; 174 175 file = get_input("Local file?"); 176 if (file == NULL || *file == '\0') 177 return; 178 179 expanded = tilde_expand(file); 180 xmodem_send(expanded); 181 free(expanded); 182 } 183 184 void 185 set_speed(void) 186 { 187 const char *s, *errstr; 188 int speed; 189 190 s = get_input("New speed?"); 191 if (s == NULL || *s == '\0') 192 return; 193 194 speed = strtonum(s, 0, UINT_MAX, &errstr); 195 if (errstr != NULL) { 196 cu_warnx("speed is %s: %s", errstr, s); 197 return; 198 } 199 200 if (set_line(speed) != 0) 201 cu_warn("tcsetattr"); 202 } 203 204 void 205 start_record(void) 206 { 207 const char *file; 208 209 if (record_file != NULL) { 210 fclose(record_file); 211 record_file = NULL; 212 } 213 214 file = get_input("Record file?"); 215 if (file == NULL || *file == '\0') 216 return; 217 218 record_file = fopen(file, "a"); 219 if (record_file == NULL) 220 cu_warnx("%s", file); 221 } 222 223 void 224 do_command(char c) 225 { 226 if (restricted && strchr("CRX$>", c) != NULL) { 227 cu_warnx("~%c command is not allowed in restricted mode", c); 228 return; 229 } 230 231 switch (c) { 232 case '.': 233 case '\004': /* ^D */ 234 event_loopexit(NULL); 235 break; 236 case '\032': /* ^Z */ 237 restore_termios(); 238 kill(getpid(), SIGTSTP); 239 set_termios(); 240 break; 241 case 'C': 242 connect_command(); 243 break; 244 case 'D': 245 ioctl(line_fd, TIOCCDTR, NULL); 246 sleep(1); 247 ioctl(line_fd, TIOCSDTR, NULL); 248 break; 249 case 'R': 250 start_record(); 251 break; 252 case 'S': 253 set_speed(); 254 break; 255 case 'X': 256 send_xmodem(); 257 break; 258 case '$': 259 pipe_command(); 260 break; 261 case '>': 262 send_file(); 263 break; 264 case '#': 265 ioctl(line_fd, TIOCSBRK, NULL); 266 sleep(1); 267 ioctl(line_fd, TIOCCBRK, NULL); 268 break; 269 case '~': 270 bufferevent_write(line_ev, "~", 1); 271 break; 272 case '?': 273 printf("\r\n" 274 "~# send break\r\n" 275 "~$ pipe local command to remote host\r\n" 276 "~> send file to remote host\r\n" 277 "~C connect program to remote host\r\n" 278 "~D de-assert DTR line briefly\r\n" 279 "~R start recording to file\r\n" 280 "~S set speed\r\n" 281 "~X send file with XMODEM\r\n" 282 "~? get this summary\r\n" 283 ); 284 break; 285 } 286 } 287