diff options
Diffstat (limited to 'ssh.c')
-rw-r--r-- | ssh.c | 196 |
1 files changed, 133 insertions, 63 deletions
@@ -40,7 +40,7 @@ | |||
40 | */ | 40 | */ |
41 | 41 | ||
42 | #include "includes.h" | 42 | #include "includes.h" |
43 | RCSID("$OpenBSD: ssh.c,v 1.224 2004/07/28 09:40:29 markus Exp $"); | 43 | RCSID("$OpenBSD: ssh.c,v 1.233 2005/03/01 17:22:06 jmc Exp $"); |
44 | 44 | ||
45 | #include <openssl/evp.h> | 45 | #include <openssl/evp.h> |
46 | #include <openssl/err.h> | 46 | #include <openssl/err.h> |
@@ -144,6 +144,9 @@ pid_t proxy_command_pid = 0; | |||
144 | /* fd to control socket */ | 144 | /* fd to control socket */ |
145 | int control_fd = -1; | 145 | int control_fd = -1; |
146 | 146 | ||
147 | /* Multiplexing control command */ | ||
148 | static u_int mux_command = SSHMUX_COMMAND_OPEN; | ||
149 | |||
147 | /* Only used in control client mode */ | 150 | /* Only used in control client mode */ |
148 | volatile sig_atomic_t control_client_terminate = 0; | 151 | volatile sig_atomic_t control_client_terminate = 0; |
149 | u_int control_server_pid = 0; | 152 | u_int control_server_pid = 0; |
@@ -154,10 +157,12 @@ static void | |||
154 | usage(void) | 157 | usage(void) |
155 | { | 158 | { |
156 | fprintf(stderr, | 159 | fprintf(stderr, |
157 | "usage: ssh [-1246AaCfghkMNnqsTtVvXxY] [-b bind_address] [-c cipher_spec]\n" | 160 | "usage: ssh [-1246AaCfgkMNnqsTtVvXxY] [-b bind_address] [-c cipher_spec]\n" |
158 | " [-D port] [-e escape_char] [-F configfile] [-i identity_file]\n" | 161 | " [-D port] [-e escape_char] [-F configfile]\n" |
159 | " [-L port:host:hostport] [-l login_name] [-m mac_spec] [-o option]\n" | 162 | " [-i identity_file] [-L [bind_address:]port:host:hostport]\n" |
160 | " [-p port] [-R port:host:hostport] [-S ctl] [user@]hostname [command]\n" | 163 | " [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n" |
164 | " [-R [bind_address:]port:host:hostport] [-S ctl_path]\n" | ||
165 | " [user@]hostname [command]\n" | ||
161 | ); | 166 | ); |
162 | exit(1); | 167 | exit(1); |
163 | } | 168 | } |
@@ -174,14 +179,13 @@ int | |||
174 | main(int ac, char **av) | 179 | main(int ac, char **av) |
175 | { | 180 | { |
176 | int i, opt, exit_status; | 181 | int i, opt, exit_status; |
177 | u_short fwd_port, fwd_host_port; | ||
178 | char sfwd_port[6], sfwd_host_port[6]; | ||
179 | char *p, *cp, *line, buf[256]; | 182 | char *p, *cp, *line, buf[256]; |
180 | struct stat st; | 183 | struct stat st; |
181 | struct passwd *pw; | 184 | struct passwd *pw; |
182 | int dummy; | 185 | int dummy; |
183 | extern int optind, optreset; | 186 | extern int optind, optreset; |
184 | extern char *optarg; | 187 | extern char *optarg; |
188 | Forward fwd; | ||
185 | 189 | ||
186 | __progname = ssh_get_progname(av[0]); | 190 | __progname = ssh_get_progname(av[0]); |
187 | init_rng(); | 191 | init_rng(); |
@@ -236,7 +240,7 @@ main(int ac, char **av) | |||
236 | 240 | ||
237 | again: | 241 | again: |
238 | while ((opt = getopt(ac, av, | 242 | while ((opt = getopt(ac, av, |
239 | "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:MNPR:S:TVXY")) != -1) { | 243 | "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:MNO:PR:S:TVXY")) != -1) { |
240 | switch (opt) { | 244 | switch (opt) { |
241 | case '1': | 245 | case '1': |
242 | options.protocol = SSH_PROTO_1; | 246 | options.protocol = SSH_PROTO_1; |
@@ -270,6 +274,14 @@ again: | |||
270 | case 'g': | 274 | case 'g': |
271 | options.gateway_ports = 1; | 275 | options.gateway_ports = 1; |
272 | break; | 276 | break; |
277 | case 'O': | ||
278 | if (strcmp(optarg, "check") == 0) | ||
279 | mux_command = SSHMUX_COMMAND_ALIVE_CHECK; | ||
280 | else if (strcmp(optarg, "exit") == 0) | ||
281 | mux_command = SSHMUX_COMMAND_TERMINATE; | ||
282 | else | ||
283 | fatal("Invalid multiplex command."); | ||
284 | break; | ||
273 | case 'P': /* deprecated */ | 285 | case 'P': /* deprecated */ |
274 | options.use_privileged_port = 0; | 286 | options.use_privileged_port = 0; |
275 | break; | 287 | break; |
@@ -285,7 +297,8 @@ again: | |||
285 | case 'i': | 297 | case 'i': |
286 | if (stat(optarg, &st) < 0) { | 298 | if (stat(optarg, &st) < 0) { |
287 | fprintf(stderr, "Warning: Identity file %s " | 299 | fprintf(stderr, "Warning: Identity file %s " |
288 | "does not exist.\n", optarg); | 300 | "not accessible: %s.\n", optarg, |
301 | strerror(errno)); | ||
289 | break; | 302 | break; |
290 | } | 303 | } |
291 | if (options.num_identity_files >= | 304 | if (options.num_identity_files >= |
@@ -316,10 +329,10 @@ again: | |||
316 | options.log_level++; | 329 | options.log_level++; |
317 | break; | 330 | break; |
318 | } | 331 | } |
319 | /* fallthrough */ | 332 | /* FALLTHROUGH */ |
320 | case 'V': | 333 | case 'V': |
321 | fprintf(stderr, "%s, %s\n", | 334 | fprintf(stderr, "%s, %s\n", |
322 | SSH_VERSION, SSLeay_version(SSLEAY_VERSION)); | 335 | SSH_RELEASE, SSLeay_version(SSLEAY_VERSION)); |
323 | if (opt == 'V') | 336 | if (opt == 'V') |
324 | exit(0); | 337 | exit(0); |
325 | break; | 338 | break; |
@@ -388,39 +401,51 @@ again: | |||
388 | break; | 401 | break; |
389 | 402 | ||
390 | case 'L': | 403 | case 'L': |
391 | case 'R': | 404 | if (parse_forward(&fwd, optarg)) |
392 | if (sscanf(optarg, "%5[0123456789]:%255[^:]:%5[0123456789]", | 405 | add_local_forward(&options, &fwd); |
393 | sfwd_port, buf, sfwd_host_port) != 3 && | 406 | else { |
394 | sscanf(optarg, "%5[0123456789]/%255[^/]/%5[0123456789]", | ||
395 | sfwd_port, buf, sfwd_host_port) != 3) { | ||
396 | fprintf(stderr, | 407 | fprintf(stderr, |
397 | "Bad forwarding specification '%s'\n", | 408 | "Bad local forwarding specification '%s'\n", |
398 | optarg); | 409 | optarg); |
399 | usage(); | 410 | exit(1); |
400 | /* NOTREACHED */ | ||
401 | } | 411 | } |
402 | if ((fwd_port = a2port(sfwd_port)) == 0 || | 412 | break; |
403 | (fwd_host_port = a2port(sfwd_host_port)) == 0) { | 413 | |
414 | case 'R': | ||
415 | if (parse_forward(&fwd, optarg)) { | ||
416 | add_remote_forward(&options, &fwd); | ||
417 | } else { | ||
404 | fprintf(stderr, | 418 | fprintf(stderr, |
405 | "Bad forwarding port(s) '%s'\n", optarg); | 419 | "Bad remote forwarding specification " |
420 | "'%s'\n", optarg); | ||
406 | exit(1); | 421 | exit(1); |
407 | } | 422 | } |
408 | if (opt == 'L') | ||
409 | add_local_forward(&options, fwd_port, buf, | ||
410 | fwd_host_port); | ||
411 | else if (opt == 'R') | ||
412 | add_remote_forward(&options, fwd_port, buf, | ||
413 | fwd_host_port); | ||
414 | break; | 423 | break; |
415 | 424 | ||
416 | case 'D': | 425 | case 'D': |
417 | fwd_port = a2port(optarg); | 426 | cp = p = xstrdup(optarg); |
418 | if (fwd_port == 0) { | 427 | memset(&fwd, '\0', sizeof(fwd)); |
428 | fwd.connect_host = "socks"; | ||
429 | if ((fwd.listen_host = hpdelim(&cp)) == NULL) { | ||
430 | fprintf(stderr, "Bad dynamic forwarding " | ||
431 | "specification '%.100s'\n", optarg); | ||
432 | exit(1); | ||
433 | } | ||
434 | if (cp != NULL) { | ||
435 | fwd.listen_port = a2port(cp); | ||
436 | fwd.listen_host = cleanhostname(fwd.listen_host); | ||
437 | } else { | ||
438 | fwd.listen_port = a2port(fwd.listen_host); | ||
439 | fwd.listen_host = ""; | ||
440 | } | ||
441 | |||
442 | if (fwd.listen_port == 0) { | ||
419 | fprintf(stderr, "Bad dynamic port '%s'\n", | 443 | fprintf(stderr, "Bad dynamic port '%s'\n", |
420 | optarg); | 444 | optarg); |
421 | exit(1); | 445 | exit(1); |
422 | } | 446 | } |
423 | add_local_forward(&options, fwd_port, "socks", 0); | 447 | add_local_forward(&options, &fwd); |
448 | xfree(p); | ||
424 | break; | 449 | break; |
425 | 450 | ||
426 | case 'C': | 451 | case 'C': |
@@ -829,14 +854,19 @@ ssh_init_forwarding(void) | |||
829 | 854 | ||
830 | /* Initiate local TCP/IP port forwardings. */ | 855 | /* Initiate local TCP/IP port forwardings. */ |
831 | for (i = 0; i < options.num_local_forwards; i++) { | 856 | for (i = 0; i < options.num_local_forwards; i++) { |
832 | debug("Connections to local port %d forwarded to remote address %.200s:%d", | 857 | debug("Local connections to %.200s:%d forwarded to remote " |
833 | options.local_forwards[i].port, | 858 | "address %.200s:%d", |
834 | options.local_forwards[i].host, | 859 | (options.local_forwards[i].listen_host == NULL) ? |
835 | options.local_forwards[i].host_port); | 860 | (options.gateway_ports ? "*" : "LOCALHOST") : |
861 | options.local_forwards[i].listen_host, | ||
862 | options.local_forwards[i].listen_port, | ||
863 | options.local_forwards[i].connect_host, | ||
864 | options.local_forwards[i].connect_port); | ||
836 | success += channel_setup_local_fwd_listener( | 865 | success += channel_setup_local_fwd_listener( |
837 | options.local_forwards[i].port, | 866 | options.local_forwards[i].listen_host, |
838 | options.local_forwards[i].host, | 867 | options.local_forwards[i].listen_port, |
839 | options.local_forwards[i].host_port, | 868 | options.local_forwards[i].connect_host, |
869 | options.local_forwards[i].connect_port, | ||
840 | options.gateway_ports); | 870 | options.gateway_ports); |
841 | } | 871 | } |
842 | if (i > 0 && success == 0) | 872 | if (i > 0 && success == 0) |
@@ -844,14 +874,17 @@ ssh_init_forwarding(void) | |||
844 | 874 | ||
845 | /* Initiate remote TCP/IP port forwardings. */ | 875 | /* Initiate remote TCP/IP port forwardings. */ |
846 | for (i = 0; i < options.num_remote_forwards; i++) { | 876 | for (i = 0; i < options.num_remote_forwards; i++) { |
847 | debug("Connections to remote port %d forwarded to local address %.200s:%d", | 877 | debug("Remote connections from %.200s:%d forwarded to " |
848 | options.remote_forwards[i].port, | 878 | "local address %.200s:%d", |
849 | options.remote_forwards[i].host, | 879 | options.remote_forwards[i].listen_host, |
850 | options.remote_forwards[i].host_port); | 880 | options.remote_forwards[i].listen_port, |
881 | options.remote_forwards[i].connect_host, | ||
882 | options.remote_forwards[i].connect_port); | ||
851 | channel_request_remote_forwarding( | 883 | channel_request_remote_forwarding( |
852 | options.remote_forwards[i].port, | 884 | options.remote_forwards[i].listen_host, |
853 | options.remote_forwards[i].host, | 885 | options.remote_forwards[i].listen_port, |
854 | options.remote_forwards[i].host_port); | 886 | options.remote_forwards[i].connect_host, |
887 | options.remote_forwards[i].connect_port); | ||
855 | } | 888 | } |
856 | } | 889 | } |
857 | 890 | ||
@@ -1027,12 +1060,12 @@ client_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt) | |||
1027 | return; | 1060 | return; |
1028 | debug("remote forward %s for: listen %d, connect %s:%d", | 1061 | debug("remote forward %s for: listen %d, connect %s:%d", |
1029 | type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", | 1062 | type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", |
1030 | options.remote_forwards[i].port, | 1063 | options.remote_forwards[i].listen_port, |
1031 | options.remote_forwards[i].host, | 1064 | options.remote_forwards[i].connect_host, |
1032 | options.remote_forwards[i].host_port); | 1065 | options.remote_forwards[i].connect_port); |
1033 | if (type == SSH2_MSG_REQUEST_FAILURE) | 1066 | if (type == SSH2_MSG_REQUEST_FAILURE) |
1034 | logit("Warning: remote port forwarding failed for listen port %d", | 1067 | logit("Warning: remote port forwarding failed for listen " |
1035 | options.remote_forwards[i].port); | 1068 | "port %d", options.remote_forwards[i].listen_port); |
1036 | } | 1069 | } |
1037 | 1070 | ||
1038 | static void | 1071 | static void |
@@ -1249,10 +1282,20 @@ static void | |||
1249 | control_client(const char *path) | 1282 | control_client(const char *path) |
1250 | { | 1283 | { |
1251 | struct sockaddr_un addr; | 1284 | struct sockaddr_un addr; |
1252 | int i, r, sock, exitval, num_env, addr_len; | 1285 | int i, r, fd, sock, exitval, num_env, addr_len; |
1253 | Buffer m; | 1286 | Buffer m; |
1254 | char *cp; | 1287 | char *term; |
1255 | extern char **environ; | 1288 | extern char **environ; |
1289 | u_int flags; | ||
1290 | |||
1291 | if (stdin_null_flag) { | ||
1292 | if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1) | ||
1293 | fatal("open(/dev/null): %s", strerror(errno)); | ||
1294 | if (dup2(fd, STDIN_FILENO) == -1) | ||
1295 | fatal("dup2: %s", strerror(errno)); | ||
1296 | if (fd > STDERR_FILENO) | ||
1297 | close(fd); | ||
1298 | } | ||
1256 | 1299 | ||
1257 | memset(&addr, '\0', sizeof(addr)); | 1300 | memset(&addr, '\0', sizeof(addr)); |
1258 | addr.sun_family = AF_UNIX; | 1301 | addr.sun_family = AF_UNIX; |
@@ -1269,26 +1312,52 @@ control_client(const char *path) | |||
1269 | if (connect(sock, (struct sockaddr*)&addr, addr_len) == -1) | 1312 | if (connect(sock, (struct sockaddr*)&addr, addr_len) == -1) |
1270 | fatal("Couldn't connect to %s: %s", path, strerror(errno)); | 1313 | fatal("Couldn't connect to %s: %s", path, strerror(errno)); |
1271 | 1314 | ||
1272 | if ((cp = getenv("TERM")) == NULL) | 1315 | if ((term = getenv("TERM")) == NULL) |
1273 | cp = ""; | 1316 | term = ""; |
1317 | |||
1318 | flags = 0; | ||
1319 | if (tty_flag) | ||
1320 | flags |= SSHMUX_FLAG_TTY; | ||
1321 | if (subsystem_flag) | ||
1322 | flags |= SSHMUX_FLAG_SUBSYS; | ||
1274 | 1323 | ||
1275 | buffer_init(&m); | 1324 | buffer_init(&m); |
1276 | 1325 | ||
1277 | /* Get PID of controlee */ | 1326 | /* Send our command to server */ |
1327 | buffer_put_int(&m, mux_command); | ||
1328 | buffer_put_int(&m, flags); | ||
1329 | if (ssh_msg_send(sock, /* version */1, &m) == -1) | ||
1330 | fatal("%s: msg_send", __func__); | ||
1331 | buffer_clear(&m); | ||
1332 | |||
1333 | /* Get authorisation status and PID of controlee */ | ||
1278 | if (ssh_msg_recv(sock, &m) == -1) | 1334 | if (ssh_msg_recv(sock, &m) == -1) |
1279 | fatal("%s: msg_recv", __func__); | 1335 | fatal("%s: msg_recv", __func__); |
1280 | if (buffer_get_char(&m) != 0) | 1336 | if (buffer_get_char(&m) != 1) |
1281 | fatal("%s: wrong version", __func__); | 1337 | fatal("%s: wrong version", __func__); |
1282 | /* Connection allowed? */ | ||
1283 | if (buffer_get_int(&m) != 1) | 1338 | if (buffer_get_int(&m) != 1) |
1284 | fatal("Connection to master denied"); | 1339 | fatal("Connection to master denied"); |
1285 | control_server_pid = buffer_get_int(&m); | 1340 | control_server_pid = buffer_get_int(&m); |
1286 | 1341 | ||
1287 | buffer_clear(&m); | 1342 | buffer_clear(&m); |
1288 | buffer_put_int(&m, tty_flag); | ||
1289 | buffer_put_int(&m, subsystem_flag); | ||
1290 | buffer_put_cstring(&m, cp); | ||
1291 | 1343 | ||
1344 | switch (mux_command) { | ||
1345 | case SSHMUX_COMMAND_ALIVE_CHECK: | ||
1346 | fprintf(stderr, "Master running (pid=%d)\r\n", | ||
1347 | control_server_pid); | ||
1348 | exit(0); | ||
1349 | case SSHMUX_COMMAND_TERMINATE: | ||
1350 | fprintf(stderr, "Exit request sent.\r\n"); | ||
1351 | exit(0); | ||
1352 | case SSHMUX_COMMAND_OPEN: | ||
1353 | /* continue below */ | ||
1354 | break; | ||
1355 | default: | ||
1356 | fatal("silly mux_command %d", mux_command); | ||
1357 | } | ||
1358 | |||
1359 | /* SSHMUX_COMMAND_OPEN */ | ||
1360 | buffer_put_cstring(&m, term); | ||
1292 | buffer_append(&command, "\0", 1); | 1361 | buffer_append(&command, "\0", 1); |
1293 | buffer_put_cstring(&m, buffer_ptr(&command)); | 1362 | buffer_put_cstring(&m, buffer_ptr(&command)); |
1294 | 1363 | ||
@@ -1310,7 +1379,7 @@ control_client(const char *path) | |||
1310 | } | 1379 | } |
1311 | } | 1380 | } |
1312 | 1381 | ||
1313 | if (ssh_msg_send(sock, /* version */0, &m) == -1) | 1382 | if (ssh_msg_send(sock, /* version */1, &m) == -1) |
1314 | fatal("%s: msg_send", __func__); | 1383 | fatal("%s: msg_send", __func__); |
1315 | 1384 | ||
1316 | mm_send_fd(sock, STDIN_FILENO); | 1385 | mm_send_fd(sock, STDIN_FILENO); |
@@ -1321,10 +1390,11 @@ control_client(const char *path) | |||
1321 | buffer_clear(&m); | 1390 | buffer_clear(&m); |
1322 | if (ssh_msg_recv(sock, &m) == -1) | 1391 | if (ssh_msg_recv(sock, &m) == -1) |
1323 | fatal("%s: msg_recv", __func__); | 1392 | fatal("%s: msg_recv", __func__); |
1324 | if (buffer_get_char(&m) != 0) | 1393 | if (buffer_get_char(&m) != 1) |
1325 | fatal("%s: master returned error", __func__); | 1394 | fatal("%s: wrong version", __func__); |
1326 | buffer_free(&m); | 1395 | buffer_free(&m); |
1327 | 1396 | ||
1397 | signal(SIGHUP, control_client_sighandler); | ||
1328 | signal(SIGINT, control_client_sighandler); | 1398 | signal(SIGINT, control_client_sighandler); |
1329 | signal(SIGTERM, control_client_sighandler); | 1399 | signal(SIGTERM, control_client_sighandler); |
1330 | signal(SIGWINCH, control_client_sigrelay); | 1400 | signal(SIGWINCH, control_client_sigrelay); |