diff options
Diffstat (limited to 'ssh.c')
-rw-r--r-- | ssh.c | 174 |
1 files changed, 142 insertions, 32 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh.c,v 1.326 2009/07/02 02:11:47 dtucker Exp $ */ | 1 | /* $OpenBSD: ssh.c,v 1.335 2010/02/26 20:29:54 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -100,10 +100,11 @@ | |||
100 | #include "match.h" | 100 | #include "match.h" |
101 | #include "msg.h" | 101 | #include "msg.h" |
102 | #include "uidswap.h" | 102 | #include "uidswap.h" |
103 | #include "roaming.h" | ||
103 | #include "version.h" | 104 | #include "version.h" |
104 | 105 | ||
105 | #ifdef SMARTCARD | 106 | #ifdef ENABLE_PKCS11 |
106 | #include "scard.h" | 107 | #include "ssh-pkcs11.h" |
107 | #endif | 108 | #endif |
108 | 109 | ||
109 | extern char *__progname; | 110 | extern char *__progname; |
@@ -132,6 +133,10 @@ int stdin_null_flag = 0; | |||
132 | */ | 133 | */ |
133 | int fork_after_authentication_flag = 0; | 134 | int fork_after_authentication_flag = 0; |
134 | 135 | ||
136 | /* forward stdio to remote host and port */ | ||
137 | char *stdio_forward_host = NULL; | ||
138 | int stdio_forward_port = 0; | ||
139 | |||
135 | /* | 140 | /* |
136 | * General data structure for command line options and options configurable | 141 | * General data structure for command line options and options configurable |
137 | * in configuration files. See readconf.h. | 142 | * in configuration files. See readconf.h. |
@@ -182,10 +187,12 @@ usage(void) | |||
182 | fprintf(stderr, | 187 | fprintf(stderr, |
183 | "usage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]\n" | 188 | "usage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]\n" |
184 | " [-D [bind_address:]port] [-e escape_char] [-F configfile]\n" | 189 | " [-D [bind_address:]port] [-e escape_char] [-F configfile]\n" |
185 | " [-i identity_file] [-L [bind_address:]port:host:hostport]\n" | 190 | " [-I pkcs11] [-i identity_file]\n" |
191 | " [-L [bind_address:]port:host:hostport]\n" | ||
186 | " [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n" | 192 | " [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n" |
187 | " [-R [bind_address:]port:host:hostport] [-S ctl_path]\n" | 193 | " [-R [bind_address:]port:host:hostport] [-S ctl_path]\n" |
188 | " [-w local_tun[:remote_tun]] [user@]hostname [command]\n" | 194 | " [-W host:port] [-w local_tun[:remote_tun]]\n" |
195 | " [user@]hostname [command]\n" | ||
189 | ); | 196 | ); |
190 | exit(255); | 197 | exit(255); |
191 | } | 198 | } |
@@ -275,7 +282,7 @@ main(int ac, char **av) | |||
275 | 282 | ||
276 | again: | 283 | again: |
277 | while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" | 284 | while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" |
278 | "ACD:F:I:KL:MNO:PR:S:TVw:XYy")) != -1) { | 285 | "ACD:F:I:KL:MNO:PR:S:TVw:W:XYy")) != -1) { |
279 | switch (opt) { | 286 | switch (opt) { |
280 | case '1': | 287 | case '1': |
281 | options.protocol = SSH_PROTO_1; | 288 | options.protocol = SSH_PROTO_1; |
@@ -313,6 +320,11 @@ main(int ac, char **av) | |||
313 | options.gateway_ports = 1; | 320 | options.gateway_ports = 1; |
314 | break; | 321 | break; |
315 | case 'O': | 322 | case 'O': |
323 | if (stdio_forward_host != NULL) | ||
324 | fatal("Cannot specify multiplexing " | ||
325 | "command with -W"); | ||
326 | else if (muxclient_command != 0) | ||
327 | fatal("Multiplexing command already specified"); | ||
316 | if (strcmp(optarg, "check") == 0) | 328 | if (strcmp(optarg, "check") == 0) |
317 | muxclient_command = SSHMUX_COMMAND_ALIVE_CHECK; | 329 | muxclient_command = SSHMUX_COMMAND_ALIVE_CHECK; |
318 | else if (strcmp(optarg, "exit") == 0) | 330 | else if (strcmp(optarg, "exit") == 0) |
@@ -351,10 +363,10 @@ main(int ac, char **av) | |||
351 | xstrdup(optarg); | 363 | xstrdup(optarg); |
352 | break; | 364 | break; |
353 | case 'I': | 365 | case 'I': |
354 | #ifdef SMARTCARD | 366 | #ifdef ENABLE_PKCS11 |
355 | options.smartcard_device = xstrdup(optarg); | 367 | options.pkcs11_provider = xstrdup(optarg); |
356 | #else | 368 | #else |
357 | fprintf(stderr, "no support for smartcards.\n"); | 369 | fprintf(stderr, "no support for PKCS#11.\n"); |
358 | #endif | 370 | #endif |
359 | break; | 371 | break; |
360 | case 't': | 372 | case 't': |
@@ -388,6 +400,26 @@ main(int ac, char **av) | |||
388 | exit(255); | 400 | exit(255); |
389 | } | 401 | } |
390 | break; | 402 | break; |
403 | case 'W': | ||
404 | if (stdio_forward_host != NULL) | ||
405 | fatal("stdio forward already specified"); | ||
406 | if (muxclient_command != 0) | ||
407 | fatal("Cannot specify stdio forward with -O"); | ||
408 | if (parse_forward(&fwd, optarg, 1, 0)) { | ||
409 | stdio_forward_host = fwd.listen_host; | ||
410 | stdio_forward_port = fwd.listen_port; | ||
411 | xfree(fwd.connect_host); | ||
412 | } else { | ||
413 | fprintf(stderr, | ||
414 | "Bad stdio forwarding specification '%s'\n", | ||
415 | optarg); | ||
416 | exit(255); | ||
417 | } | ||
418 | no_tty_flag = 1; | ||
419 | no_shell_flag = 1; | ||
420 | options.clear_forwardings = 1; | ||
421 | options.exit_on_forward_failure = 1; | ||
422 | break; | ||
391 | case 'q': | 423 | case 'q': |
392 | if (options.log_level == SYSLOG_LEVEL_QUIET) { | 424 | if (options.log_level == SYSLOG_LEVEL_QUIET) { |
393 | options.log_level = SYSLOG_LEVEL_SILENT; | 425 | options.log_level = SYSLOG_LEVEL_SILENT; |
@@ -532,7 +564,7 @@ main(int ac, char **av) | |||
532 | ac -= optind; | 564 | ac -= optind; |
533 | av += optind; | 565 | av += optind; |
534 | 566 | ||
535 | if (ac > 0 && !host && **av != '-') { | 567 | if (ac > 0 && !host) { |
536 | if (strrchr(*av, '@')) { | 568 | if (strrchr(*av, '@')) { |
537 | p = xstrdup(*av); | 569 | p = xstrdup(*av); |
538 | cp = strrchr(p, '@'); | 570 | cp = strrchr(p, '@'); |
@@ -875,11 +907,48 @@ ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) | |||
875 | } | 907 | } |
876 | 908 | ||
877 | static void | 909 | static void |
910 | client_cleanup_stdio_fwd(int id, void *arg) | ||
911 | { | ||
912 | debug("stdio forwarding: done"); | ||
913 | cleanup_exit(0); | ||
914 | } | ||
915 | |||
916 | static int | ||
917 | client_setup_stdio_fwd(const char *host_to_connect, u_short port_to_connect) | ||
918 | { | ||
919 | Channel *c; | ||
920 | int in, out; | ||
921 | |||
922 | debug3("client_setup_stdio_fwd %s:%d", host_to_connect, | ||
923 | port_to_connect); | ||
924 | |||
925 | in = dup(STDIN_FILENO); | ||
926 | out = dup(STDOUT_FILENO); | ||
927 | if (in < 0 || out < 0) | ||
928 | fatal("channel_connect_stdio_fwd: dup() in/out failed"); | ||
929 | |||
930 | if ((c = channel_connect_stdio_fwd(host_to_connect, port_to_connect, | ||
931 | in, out)) == NULL) | ||
932 | return 0; | ||
933 | channel_register_cleanup(c->self, client_cleanup_stdio_fwd, 0); | ||
934 | return 1; | ||
935 | } | ||
936 | |||
937 | static void | ||
878 | ssh_init_forwarding(void) | 938 | ssh_init_forwarding(void) |
879 | { | 939 | { |
880 | int success = 0; | 940 | int success = 0; |
881 | int i; | 941 | int i; |
882 | 942 | ||
943 | if (stdio_forward_host != NULL) { | ||
944 | if (!compat20) { | ||
945 | fatal("stdio forwarding require Protocol 2"); | ||
946 | } | ||
947 | if (!client_setup_stdio_fwd(stdio_forward_host, | ||
948 | stdio_forward_port)) | ||
949 | fatal("Failed to connect in stdio forward mode."); | ||
950 | } | ||
951 | |||
883 | /* Initiate local TCP/IP port forwardings. */ | 952 | /* Initiate local TCP/IP port forwardings. */ |
884 | for (i = 0; i < options.num_local_forwards; i++) { | 953 | for (i = 0; i < options.num_local_forwards; i++) { |
885 | debug("Local connections to %.200s:%d forwarded to remote " | 954 | debug("Local connections to %.200s:%d forwarded to remote " |
@@ -1227,6 +1296,9 @@ ssh_session2(void) | |||
1227 | fatal("daemon() failed: %.200s", strerror(errno)); | 1296 | fatal("daemon() failed: %.200s", strerror(errno)); |
1228 | } | 1297 | } |
1229 | 1298 | ||
1299 | if (options.use_roaming) | ||
1300 | request_roaming(); | ||
1301 | |||
1230 | return client_loop(tty_flag, tty_flag ? | 1302 | return client_loop(tty_flag, tty_flag ? |
1231 | options.escape_char : SSH_ESCAPECHAR_NONE, id); | 1303 | options.escape_char : SSH_ESCAPECHAR_NONE, id); |
1232 | } | 1304 | } |
@@ -1239,31 +1311,37 @@ load_public_identity_files(void) | |||
1239 | int i = 0; | 1311 | int i = 0; |
1240 | Key *public; | 1312 | Key *public; |
1241 | struct passwd *pw; | 1313 | struct passwd *pw; |
1242 | #ifdef SMARTCARD | 1314 | u_int n_ids; |
1315 | char *identity_files[SSH_MAX_IDENTITY_FILES]; | ||
1316 | Key *identity_keys[SSH_MAX_IDENTITY_FILES]; | ||
1317 | #ifdef ENABLE_PKCS11 | ||
1243 | Key **keys; | 1318 | Key **keys; |
1319 | int nkeys; | ||
1320 | #endif /* PKCS11 */ | ||
1244 | 1321 | ||
1245 | if (options.smartcard_device != NULL && | 1322 | n_ids = 0; |
1323 | bzero(identity_files, sizeof(identity_files)); | ||
1324 | bzero(identity_keys, sizeof(identity_keys)); | ||
1325 | |||
1326 | #ifdef ENABLE_PKCS11 | ||
1327 | if (options.pkcs11_provider != NULL && | ||
1246 | options.num_identity_files < SSH_MAX_IDENTITY_FILES && | 1328 | options.num_identity_files < SSH_MAX_IDENTITY_FILES && |
1247 | (keys = sc_get_keys(options.smartcard_device, NULL)) != NULL) { | 1329 | (pkcs11_init(!options.batch_mode) == 0) && |
1248 | int count = 0; | 1330 | (nkeys = pkcs11_add_provider(options.pkcs11_provider, NULL, |
1249 | for (i = 0; keys[i] != NULL; i++) { | 1331 | &keys)) > 0) { |
1250 | count++; | 1332 | for (i = 0; i < nkeys; i++) { |
1251 | memmove(&options.identity_files[1], | 1333 | if (n_ids >= SSH_MAX_IDENTITY_FILES) { |
1252 | &options.identity_files[0], | 1334 | key_free(keys[i]); |
1253 | sizeof(char *) * (SSH_MAX_IDENTITY_FILES - 1)); | 1335 | continue; |
1254 | memmove(&options.identity_keys[1], | 1336 | } |
1255 | &options.identity_keys[0], | 1337 | identity_keys[n_ids] = keys[i]; |
1256 | sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1)); | 1338 | identity_files[n_ids] = |
1257 | options.num_identity_files++; | 1339 | xstrdup(options.pkcs11_provider); /* XXX */ |
1258 | options.identity_keys[0] = keys[i]; | 1340 | n_ids++; |
1259 | options.identity_files[0] = sc_get_key_label(keys[i]); | ||
1260 | } | 1341 | } |
1261 | if (options.num_identity_files > SSH_MAX_IDENTITY_FILES) | ||
1262 | options.num_identity_files = SSH_MAX_IDENTITY_FILES; | ||
1263 | i = count; | ||
1264 | xfree(keys); | 1342 | xfree(keys); |
1265 | } | 1343 | } |
1266 | #endif /* SMARTCARD */ | 1344 | #endif /* ENABLE_PKCS11 */ |
1267 | if ((pw = getpwuid(original_real_uid)) == NULL) | 1345 | if ((pw = getpwuid(original_real_uid)) == NULL) |
1268 | fatal("load_public_identity_files: getpwuid failed"); | 1346 | fatal("load_public_identity_files: getpwuid failed"); |
1269 | pwname = xstrdup(pw->pw_name); | 1347 | pwname = xstrdup(pw->pw_name); |
@@ -1271,7 +1349,11 @@ load_public_identity_files(void) | |||
1271 | if (gethostname(thishost, sizeof(thishost)) == -1) | 1349 | if (gethostname(thishost, sizeof(thishost)) == -1) |
1272 | fatal("load_public_identity_files: gethostname: %s", | 1350 | fatal("load_public_identity_files: gethostname: %s", |
1273 | strerror(errno)); | 1351 | strerror(errno)); |
1274 | for (; i < options.num_identity_files; i++) { | 1352 | for (i = 0; i < options.num_identity_files; i++) { |
1353 | if (n_ids >= SSH_MAX_IDENTITY_FILES) { | ||
1354 | xfree(options.identity_files[i]); | ||
1355 | continue; | ||
1356 | } | ||
1275 | cp = tilde_expand_filename(options.identity_files[i], | 1357 | cp = tilde_expand_filename(options.identity_files[i], |
1276 | original_real_uid); | 1358 | original_real_uid); |
1277 | filename = percent_expand(cp, "d", pwdir, | 1359 | filename = percent_expand(cp, "d", pwdir, |
@@ -1298,9 +1380,37 @@ load_public_identity_files(void) | |||
1298 | } | 1380 | } |
1299 | } | 1381 | } |
1300 | xfree(options.identity_files[i]); | 1382 | xfree(options.identity_files[i]); |
1301 | options.identity_files[i] = filename; | 1383 | identity_files[n_ids] = filename; |
1302 | options.identity_keys[i] = public; | 1384 | identity_keys[n_ids] = public; |
1385 | |||
1386 | if (++n_ids >= SSH_MAX_IDENTITY_FILES) | ||
1387 | continue; | ||
1388 | |||
1389 | /* Try to add the certificate variant too */ | ||
1390 | xasprintf(&cp, "%s-cert", filename); | ||
1391 | public = key_load_public(cp, NULL); | ||
1392 | debug("identity file %s type %d", cp, | ||
1393 | public ? public->type : -1); | ||
1394 | if (public == NULL) { | ||
1395 | xfree(cp); | ||
1396 | continue; | ||
1397 | } | ||
1398 | if (!key_is_cert(public)) { | ||
1399 | debug("%s: key %s type %s is not a certificate", | ||
1400 | __func__, cp, key_type(public)); | ||
1401 | key_free(public); | ||
1402 | xfree(cp); | ||
1403 | continue; | ||
1404 | } | ||
1405 | identity_keys[n_ids] = public; | ||
1406 | /* point to the original path, most likely the private key */ | ||
1407 | identity_files[n_ids] = xstrdup(filename); | ||
1408 | n_ids++; | ||
1303 | } | 1409 | } |
1410 | options.num_identity_files = n_ids; | ||
1411 | memcpy(options.identity_files, identity_files, sizeof(identity_files)); | ||
1412 | memcpy(options.identity_keys, identity_keys, sizeof(identity_keys)); | ||
1413 | |||
1304 | bzero(pwname, strlen(pwname)); | 1414 | bzero(pwname, strlen(pwname)); |
1305 | xfree(pwname); | 1415 | xfree(pwname); |
1306 | bzero(pwdir, strlen(pwdir)); | 1416 | bzero(pwdir, strlen(pwdir)); |