diff options
author | Colin Watson <cjwatson@debian.org> | 2005-05-25 11:01:01 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2005-05-25 11:01:01 +0000 |
commit | e88de75a1a236779a10e8ccbcc51d25308be8840 (patch) | |
tree | 7495477a2a7d0cac17a9fcded020b6ea816182ef /ssh.c | |
parent | 30a0f9443782cd9d7308acd09430bf586186aa55 (diff) | |
parent | 5d05471f6657646d1d6500c7c43134462c407ee6 (diff) |
Merge 4.0p1 to the trunk.
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; |
@@ -393,39 +406,51 @@ again: | |||
393 | break; | 406 | break; |
394 | 407 | ||
395 | case 'L': | 408 | case 'L': |
396 | case 'R': | 409 | if (parse_forward(&fwd, optarg)) |
397 | if (sscanf(optarg, "%5[0123456789]:%255[^:]:%5[0123456789]", | 410 | add_local_forward(&options, &fwd); |
398 | sfwd_port, buf, sfwd_host_port) != 3 && | 411 | else { |
399 | sscanf(optarg, "%5[0123456789]/%255[^/]/%5[0123456789]", | ||
400 | sfwd_port, buf, sfwd_host_port) != 3) { | ||
401 | fprintf(stderr, | 412 | fprintf(stderr, |
402 | "Bad forwarding specification '%s'\n", | 413 | "Bad local forwarding specification '%s'\n", |
403 | optarg); | 414 | optarg); |
404 | usage(); | 415 | exit(1); |
405 | /* NOTREACHED */ | ||
406 | } | 416 | } |
407 | if ((fwd_port = a2port(sfwd_port)) == 0 || | 417 | break; |
408 | (fwd_host_port = a2port(sfwd_host_port)) == 0) { | 418 | |
419 | case 'R': | ||
420 | if (parse_forward(&fwd, optarg)) { | ||
421 | add_remote_forward(&options, &fwd); | ||
422 | } else { | ||
409 | fprintf(stderr, | 423 | fprintf(stderr, |
410 | "Bad forwarding port(s) '%s'\n", optarg); | 424 | "Bad remote forwarding specification " |
425 | "'%s'\n", optarg); | ||
411 | exit(1); | 426 | exit(1); |
412 | } | 427 | } |
413 | if (opt == 'L') | ||
414 | add_local_forward(&options, fwd_port, buf, | ||
415 | fwd_host_port); | ||
416 | else if (opt == 'R') | ||
417 | add_remote_forward(&options, fwd_port, buf, | ||
418 | fwd_host_port); | ||
419 | break; | 428 | break; |
420 | 429 | ||
421 | case 'D': | 430 | case 'D': |
422 | fwd_port = a2port(optarg); | 431 | cp = p = xstrdup(optarg); |
423 | if (fwd_port == 0) { | 432 | memset(&fwd, '\0', sizeof(fwd)); |
433 | fwd.connect_host = "socks"; | ||
434 | if ((fwd.listen_host = hpdelim(&cp)) == NULL) { | ||
435 | fprintf(stderr, "Bad dynamic forwarding " | ||
436 | "specification '%.100s'\n", optarg); | ||
437 | exit(1); | ||
438 | } | ||
439 | if (cp != NULL) { | ||
440 | fwd.listen_port = a2port(cp); | ||
441 | fwd.listen_host = cleanhostname(fwd.listen_host); | ||
442 | } else { | ||
443 | fwd.listen_port = a2port(fwd.listen_host); | ||
444 | fwd.listen_host = ""; | ||
445 | } | ||
446 | |||
447 | if (fwd.listen_port == 0) { | ||
424 | fprintf(stderr, "Bad dynamic port '%s'\n", | 448 | fprintf(stderr, "Bad dynamic port '%s'\n", |
425 | optarg); | 449 | optarg); |
426 | exit(1); | 450 | exit(1); |
427 | } | 451 | } |
428 | add_local_forward(&options, fwd_port, "socks", 0); | 452 | add_local_forward(&options, &fwd); |
453 | xfree(p); | ||
429 | break; | 454 | break; |
430 | 455 | ||
431 | case 'C': | 456 | case 'C': |
@@ -834,14 +859,19 @@ ssh_init_forwarding(void) | |||
834 | 859 | ||
835 | /* Initiate local TCP/IP port forwardings. */ | 860 | /* Initiate local TCP/IP port forwardings. */ |
836 | for (i = 0; i < options.num_local_forwards; i++) { | 861 | for (i = 0; i < options.num_local_forwards; i++) { |
837 | debug("Connections to local port %d forwarded to remote address %.200s:%d", | 862 | debug("Local connections to %.200s:%d forwarded to remote " |
838 | options.local_forwards[i].port, | 863 | "address %.200s:%d", |
839 | options.local_forwards[i].host, | 864 | (options.local_forwards[i].listen_host == NULL) ? |
840 | options.local_forwards[i].host_port); | 865 | (options.gateway_ports ? "*" : "LOCALHOST") : |
866 | options.local_forwards[i].listen_host, | ||
867 | options.local_forwards[i].listen_port, | ||
868 | options.local_forwards[i].connect_host, | ||
869 | options.local_forwards[i].connect_port); | ||
841 | success += channel_setup_local_fwd_listener( | 870 | success += channel_setup_local_fwd_listener( |
842 | options.local_forwards[i].port, | 871 | options.local_forwards[i].listen_host, |
843 | options.local_forwards[i].host, | 872 | options.local_forwards[i].listen_port, |
844 | options.local_forwards[i].host_port, | 873 | options.local_forwards[i].connect_host, |
874 | options.local_forwards[i].connect_port, | ||
845 | options.gateway_ports); | 875 | options.gateway_ports); |
846 | } | 876 | } |
847 | if (i > 0 && success == 0) | 877 | if (i > 0 && success == 0) |
@@ -849,14 +879,17 @@ ssh_init_forwarding(void) | |||
849 | 879 | ||
850 | /* Initiate remote TCP/IP port forwardings. */ | 880 | /* Initiate remote TCP/IP port forwardings. */ |
851 | for (i = 0; i < options.num_remote_forwards; i++) { | 881 | for (i = 0; i < options.num_remote_forwards; i++) { |
852 | debug("Connections to remote port %d forwarded to local address %.200s:%d", | 882 | debug("Remote connections from %.200s:%d forwarded to " |
853 | options.remote_forwards[i].port, | 883 | "local address %.200s:%d", |
854 | options.remote_forwards[i].host, | 884 | options.remote_forwards[i].listen_host, |
855 | options.remote_forwards[i].host_port); | 885 | options.remote_forwards[i].listen_port, |
886 | options.remote_forwards[i].connect_host, | ||
887 | options.remote_forwards[i].connect_port); | ||
856 | channel_request_remote_forwarding( | 888 | channel_request_remote_forwarding( |
857 | options.remote_forwards[i].port, | 889 | options.remote_forwards[i].listen_host, |
858 | options.remote_forwards[i].host, | 890 | options.remote_forwards[i].listen_port, |
859 | options.remote_forwards[i].host_port); | 891 | options.remote_forwards[i].connect_host, |
892 | options.remote_forwards[i].connect_port); | ||
860 | } | 893 | } |
861 | } | 894 | } |
862 | 895 | ||
@@ -1032,12 +1065,12 @@ client_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt) | |||
1032 | return; | 1065 | return; |
1033 | debug("remote forward %s for: listen %d, connect %s:%d", | 1066 | debug("remote forward %s for: listen %d, connect %s:%d", |
1034 | type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", | 1067 | type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", |
1035 | options.remote_forwards[i].port, | 1068 | options.remote_forwards[i].listen_port, |
1036 | options.remote_forwards[i].host, | 1069 | options.remote_forwards[i].connect_host, |
1037 | options.remote_forwards[i].host_port); | 1070 | options.remote_forwards[i].connect_port); |
1038 | if (type == SSH2_MSG_REQUEST_FAILURE) | 1071 | if (type == SSH2_MSG_REQUEST_FAILURE) |
1039 | logit("Warning: remote port forwarding failed for listen port %d", | 1072 | logit("Warning: remote port forwarding failed for listen " |
1040 | options.remote_forwards[i].port); | 1073 | "port %d", options.remote_forwards[i].listen_port); |
1041 | } | 1074 | } |
1042 | 1075 | ||
1043 | static void | 1076 | static void |
@@ -1254,10 +1287,20 @@ static void | |||
1254 | control_client(const char *path) | 1287 | control_client(const char *path) |
1255 | { | 1288 | { |
1256 | struct sockaddr_un addr; | 1289 | struct sockaddr_un addr; |
1257 | int i, r, sock, exitval, num_env, addr_len; | 1290 | int i, r, fd, sock, exitval, num_env, addr_len; |
1258 | Buffer m; | 1291 | Buffer m; |
1259 | char *cp; | 1292 | char *term; |
1260 | extern char **environ; | 1293 | extern char **environ; |
1294 | u_int flags; | ||
1295 | |||
1296 | if (stdin_null_flag) { | ||
1297 | if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1) | ||
1298 | fatal("open(/dev/null): %s", strerror(errno)); | ||
1299 | if (dup2(fd, STDIN_FILENO) == -1) | ||
1300 | fatal("dup2: %s", strerror(errno)); | ||
1301 | if (fd > STDERR_FILENO) | ||
1302 | close(fd); | ||
1303 | } | ||
1261 | 1304 | ||
1262 | memset(&addr, '\0', sizeof(addr)); | 1305 | memset(&addr, '\0', sizeof(addr)); |
1263 | addr.sun_family = AF_UNIX; | 1306 | addr.sun_family = AF_UNIX; |
@@ -1274,26 +1317,52 @@ control_client(const char *path) | |||
1274 | if (connect(sock, (struct sockaddr*)&addr, addr_len) == -1) | 1317 | if (connect(sock, (struct sockaddr*)&addr, addr_len) == -1) |
1275 | fatal("Couldn't connect to %s: %s", path, strerror(errno)); | 1318 | fatal("Couldn't connect to %s: %s", path, strerror(errno)); |
1276 | 1319 | ||
1277 | if ((cp = getenv("TERM")) == NULL) | 1320 | if ((term = getenv("TERM")) == NULL) |
1278 | cp = ""; | 1321 | term = ""; |
1322 | |||
1323 | flags = 0; | ||
1324 | if (tty_flag) | ||
1325 | flags |= SSHMUX_FLAG_TTY; | ||
1326 | if (subsystem_flag) | ||
1327 | flags |= SSHMUX_FLAG_SUBSYS; | ||
1279 | 1328 | ||
1280 | buffer_init(&m); | 1329 | buffer_init(&m); |
1281 | 1330 | ||
1282 | /* Get PID of controlee */ | 1331 | /* Send our command to server */ |
1332 | buffer_put_int(&m, mux_command); | ||
1333 | buffer_put_int(&m, flags); | ||
1334 | if (ssh_msg_send(sock, /* version */1, &m) == -1) | ||
1335 | fatal("%s: msg_send", __func__); | ||
1336 | buffer_clear(&m); | ||
1337 | |||
1338 | /* Get authorisation status and PID of controlee */ | ||
1283 | if (ssh_msg_recv(sock, &m) == -1) | 1339 | if (ssh_msg_recv(sock, &m) == -1) |
1284 | fatal("%s: msg_recv", __func__); | 1340 | fatal("%s: msg_recv", __func__); |
1285 | if (buffer_get_char(&m) != 0) | 1341 | if (buffer_get_char(&m) != 1) |
1286 | fatal("%s: wrong version", __func__); | 1342 | fatal("%s: wrong version", __func__); |
1287 | /* Connection allowed? */ | ||
1288 | if (buffer_get_int(&m) != 1) | 1343 | if (buffer_get_int(&m) != 1) |
1289 | fatal("Connection to master denied"); | 1344 | fatal("Connection to master denied"); |
1290 | control_server_pid = buffer_get_int(&m); | 1345 | control_server_pid = buffer_get_int(&m); |
1291 | 1346 | ||
1292 | buffer_clear(&m); | 1347 | buffer_clear(&m); |
1293 | buffer_put_int(&m, tty_flag); | ||
1294 | buffer_put_int(&m, subsystem_flag); | ||
1295 | buffer_put_cstring(&m, cp); | ||
1296 | 1348 | ||
1349 | switch (mux_command) { | ||
1350 | case SSHMUX_COMMAND_ALIVE_CHECK: | ||
1351 | fprintf(stderr, "Master running (pid=%d)\r\n", | ||
1352 | control_server_pid); | ||
1353 | exit(0); | ||
1354 | case SSHMUX_COMMAND_TERMINATE: | ||
1355 | fprintf(stderr, "Exit request sent.\r\n"); | ||
1356 | exit(0); | ||
1357 | case SSHMUX_COMMAND_OPEN: | ||
1358 | /* continue below */ | ||
1359 | break; | ||
1360 | default: | ||
1361 | fatal("silly mux_command %d", mux_command); | ||
1362 | } | ||
1363 | |||
1364 | /* SSHMUX_COMMAND_OPEN */ | ||
1365 | buffer_put_cstring(&m, term); | ||
1297 | buffer_append(&command, "\0", 1); | 1366 | buffer_append(&command, "\0", 1); |
1298 | buffer_put_cstring(&m, buffer_ptr(&command)); | 1367 | buffer_put_cstring(&m, buffer_ptr(&command)); |
1299 | 1368 | ||
@@ -1315,7 +1384,7 @@ control_client(const char *path) | |||
1315 | } | 1384 | } |
1316 | } | 1385 | } |
1317 | 1386 | ||
1318 | if (ssh_msg_send(sock, /* version */0, &m) == -1) | 1387 | if (ssh_msg_send(sock, /* version */1, &m) == -1) |
1319 | fatal("%s: msg_send", __func__); | 1388 | fatal("%s: msg_send", __func__); |
1320 | 1389 | ||
1321 | mm_send_fd(sock, STDIN_FILENO); | 1390 | mm_send_fd(sock, STDIN_FILENO); |
@@ -1326,10 +1395,11 @@ control_client(const char *path) | |||
1326 | buffer_clear(&m); | 1395 | buffer_clear(&m); |
1327 | if (ssh_msg_recv(sock, &m) == -1) | 1396 | if (ssh_msg_recv(sock, &m) == -1) |
1328 | fatal("%s: msg_recv", __func__); | 1397 | fatal("%s: msg_recv", __func__); |
1329 | if (buffer_get_char(&m) != 0) | 1398 | if (buffer_get_char(&m) != 1) |
1330 | fatal("%s: master returned error", __func__); | 1399 | fatal("%s: wrong version", __func__); |
1331 | buffer_free(&m); | 1400 | buffer_free(&m); |
1332 | 1401 | ||
1402 | signal(SIGHUP, control_client_sighandler); | ||
1333 | signal(SIGINT, control_client_sighandler); | 1403 | signal(SIGINT, control_client_sighandler); |
1334 | signal(SIGTERM, control_client_sighandler); | 1404 | signal(SIGTERM, control_client_sighandler); |
1335 | signal(SIGWINCH, control_client_sigrelay); | 1405 | signal(SIGWINCH, control_client_sigrelay); |