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