diff options
author | djm@openbsd.org <djm@openbsd.org> | 2014-10-08 22:20:25 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2014-10-13 11:41:48 +1100 |
commit | 957fbceb0f3166e41b76fdb54075ab3b9cc84cba (patch) | |
tree | 7c8bc1f0090201400383e51d84a7fda79995e513 | |
parent | 5c0dafd38bf66feeeb45fa0741a5baf5ad8039ba (diff) |
upstream commit
Tweak config reparsing with host canonicalisation
Make the second pass through the config files always run when
hostname canonicalisation is enabled.
Add a "Match canonical" criteria that allows ssh_config Match
blocks to trigger only in the second config pass.
Add a -G option to ssh that causes it to parse its configuration
and dump the result to stdout, similar to "sshd -T"
Allow ssh_config Port options set in the second config parse
phase to be applied (they were being ignored).
bz#2267 bz#2286; ok markus
-rw-r--r-- | readconf.c | 450 | ||||
-rw-r--r-- | readconf.h | 10 | ||||
-rw-r--r-- | ssh-keysign.c | 4 | ||||
-rw-r--r-- | ssh.1 | 14 | ||||
-rw-r--r-- | ssh.c | 80 | ||||
-rw-r--r-- | ssh_config.5 | 55 |
6 files changed, 504 insertions, 109 deletions
diff --git a/readconf.c b/readconf.c index 7948ce1cd..869a1c4d8 100644 --- a/readconf.c +++ b/readconf.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: readconf.c,v 1.220 2014/07/15 15:54:14 millert Exp $ */ | 1 | /* $OpenBSD: readconf.c,v 1.221 2014/10/08 22:20:25 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 |
@@ -41,6 +41,9 @@ | |||
41 | #ifdef HAVE_UTIL_H | 41 | #ifdef HAVE_UTIL_H |
42 | #include <util.h> | 42 | #include <util.h> |
43 | #endif | 43 | #endif |
44 | #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) | ||
45 | # include <vis.h> | ||
46 | #endif | ||
44 | 47 | ||
45 | #include "xmalloc.h" | 48 | #include "xmalloc.h" |
46 | #include "ssh.h" | 49 | #include "ssh.h" |
@@ -56,6 +59,7 @@ | |||
56 | #include "kex.h" | 59 | #include "kex.h" |
57 | #include "mac.h" | 60 | #include "mac.h" |
58 | #include "uidswap.h" | 61 | #include "uidswap.h" |
62 | #include "myproposal.h" | ||
59 | 63 | ||
60 | /* Format of the configuration file: | 64 | /* Format of the configuration file: |
61 | 65 | ||
@@ -135,7 +139,7 @@ typedef enum { | |||
135 | oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, | 139 | oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, |
136 | oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts, | 140 | oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts, |
137 | oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs, | 141 | oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs, |
138 | oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication, | 142 | oPubkeyAuthentication, |
139 | oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, | 143 | oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, |
140 | oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, | 144 | oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, |
141 | oHostKeyAlgorithms, oBindAddress, oPKCS11Provider, | 145 | oHostKeyAlgorithms, oBindAddress, oPKCS11Provider, |
@@ -212,7 +216,7 @@ static struct { | |||
212 | { "globalknownhostsfile", oGlobalKnownHostsFile }, | 216 | { "globalknownhostsfile", oGlobalKnownHostsFile }, |
213 | { "globalknownhostsfile2", oDeprecated }, | 217 | { "globalknownhostsfile2", oDeprecated }, |
214 | { "userknownhostsfile", oUserKnownHostsFile }, | 218 | { "userknownhostsfile", oUserKnownHostsFile }, |
215 | { "userknownhostsfile2", oDeprecated }, | 219 | { "userknownhostsfile2", oDeprecated }, |
216 | { "connectionattempts", oConnectionAttempts }, | 220 | { "connectionattempts", oConnectionAttempts }, |
217 | { "batchmode", oBatchMode }, | 221 | { "batchmode", oBatchMode }, |
218 | { "checkhostip", oCheckHostIP }, | 222 | { "checkhostip", oCheckHostIP }, |
@@ -466,7 +470,7 @@ execute_in_shell(const char *cmd) | |||
466 | if (!WIFEXITED(status)) { | 470 | if (!WIFEXITED(status)) { |
467 | error("command '%.100s' exited abnormally", cmd); | 471 | error("command '%.100s' exited abnormally", cmd); |
468 | return -1; | 472 | return -1; |
469 | } | 473 | } |
470 | debug3("command returned status %d", WEXITSTATUS(status)); | 474 | debug3("command returned status %d", WEXITSTATUS(status)); |
471 | return WEXITSTATUS(status); | 475 | return WEXITSTATUS(status); |
472 | } | 476 | } |
@@ -476,11 +480,12 @@ execute_in_shell(const char *cmd) | |||
476 | */ | 480 | */ |
477 | static int | 481 | static int |
478 | match_cfg_line(Options *options, char **condition, struct passwd *pw, | 482 | match_cfg_line(Options *options, char **condition, struct passwd *pw, |
479 | const char *host_arg, const char *filename, int linenum) | 483 | const char *host_arg, const char *original_host, int post_canon, |
484 | const char *filename, int linenum) | ||
480 | { | 485 | { |
481 | char *arg, *attrib, *cmd, *cp = *condition, *host; | 486 | char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria; |
482 | const char *ruser; | 487 | const char *ruser; |
483 | int r, port, result = 1, attributes = 0; | 488 | int r, port, this_result, result = 1, attributes = 0, negate; |
484 | size_t len; | 489 | size_t len; |
485 | char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; | 490 | char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; |
486 | 491 | ||
@@ -497,21 +502,38 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw, | |||
497 | } else | 502 | } else |
498 | host = xstrdup(host_arg); | 503 | host = xstrdup(host_arg); |
499 | 504 | ||
500 | debug3("checking match for '%s' host %s", cp, host); | 505 | debug2("checking match for '%s' host %s originally %s", |
501 | while ((attrib = strdelim(&cp)) && *attrib != '\0') { | 506 | cp, host, original_host); |
502 | attributes++; | 507 | while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') { |
508 | criteria = NULL; | ||
509 | this_result = 1; | ||
510 | if ((negate = attrib[0] == '!')) | ||
511 | attrib++; | ||
512 | /* criteria "all" and "canonical" have no argument */ | ||
503 | if (strcasecmp(attrib, "all") == 0) { | 513 | if (strcasecmp(attrib, "all") == 0) { |
504 | if (attributes != 1 || | 514 | if (attributes > 1 || |
505 | ((arg = strdelim(&cp)) != NULL && *arg != '\0')) { | 515 | ((arg = strdelim(&cp)) != NULL && *arg != '\0')) { |
506 | error("'all' cannot be combined with other " | 516 | error("%.200s line %d: '%s' cannot be combined " |
507 | "Match attributes"); | 517 | "with other Match attributes", |
518 | filename, linenum, oattrib); | ||
508 | result = -1; | 519 | result = -1; |
509 | goto out; | 520 | goto out; |
510 | } | 521 | } |
511 | *condition = cp; | 522 | if (result) |
512 | result = 1; | 523 | result = negate ? 0 : 1; |
513 | goto out; | 524 | goto out; |
514 | } | 525 | } |
526 | attributes++; | ||
527 | if (strcasecmp(attrib, "canonical") == 0) { | ||
528 | r = !!post_canon; /* force bitmask member to boolean */ | ||
529 | if (r == (negate ? 1 : 0)) | ||
530 | this_result = result = 0; | ||
531 | debug3("%.200s line %d: %smatched '%s'", | ||
532 | filename, linenum, | ||
533 | this_result ? "" : "not ", oattrib); | ||
534 | continue; | ||
535 | } | ||
536 | /* All other criteria require an argument */ | ||
515 | if ((arg = strdelim(&cp)) == NULL || *arg == '\0') { | 537 | if ((arg = strdelim(&cp)) == NULL || *arg == '\0') { |
516 | error("Missing Match criteria for %s", attrib); | 538 | error("Missing Match criteria for %s", attrib); |
517 | result = -1; | 539 | result = -1; |
@@ -519,31 +541,25 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw, | |||
519 | } | 541 | } |
520 | len = strlen(arg); | 542 | len = strlen(arg); |
521 | if (strcasecmp(attrib, "host") == 0) { | 543 | if (strcasecmp(attrib, "host") == 0) { |
522 | if (match_hostname(host, arg, len) != 1) | 544 | criteria = xstrdup(host); |
523 | result = 0; | 545 | r = match_hostname(host, arg, len) == 1; |
524 | else | 546 | if (r == (negate ? 1 : 0)) |
525 | debug("%.200s line %d: matched 'Host %.100s' ", | 547 | this_result = result = 0; |
526 | filename, linenum, host); | ||
527 | } else if (strcasecmp(attrib, "originalhost") == 0) { | 548 | } else if (strcasecmp(attrib, "originalhost") == 0) { |
528 | if (match_hostname(host_arg, arg, len) != 1) | 549 | criteria = xstrdup(original_host); |
529 | result = 0; | 550 | r = match_hostname(original_host, arg, len) == 1; |
530 | else | 551 | if (r == (negate ? 1 : 0)) |
531 | debug("%.200s line %d: matched " | 552 | this_result = result = 0; |
532 | "'OriginalHost %.100s' ", | ||
533 | filename, linenum, host_arg); | ||
534 | } else if (strcasecmp(attrib, "user") == 0) { | 553 | } else if (strcasecmp(attrib, "user") == 0) { |
535 | if (match_pattern_list(ruser, arg, len, 0) != 1) | 554 | criteria = xstrdup(ruser); |
536 | result = 0; | 555 | r = match_pattern_list(ruser, arg, len, 0) == 1; |
537 | else | 556 | if (r == (negate ? 1 : 0)) |
538 | debug("%.200s line %d: matched 'User %.100s' ", | 557 | this_result = result = 0; |
539 | filename, linenum, ruser); | ||
540 | } else if (strcasecmp(attrib, "localuser") == 0) { | 558 | } else if (strcasecmp(attrib, "localuser") == 0) { |
541 | if (match_pattern_list(pw->pw_name, arg, len, 0) != 1) | 559 | criteria = xstrdup(pw->pw_name); |
542 | result = 0; | 560 | r = match_pattern_list(pw->pw_name, arg, len, 0) == 1; |
543 | else | 561 | if (r == (negate ? 1 : 0)) |
544 | debug("%.200s line %d: matched " | 562 | this_result = result = 0; |
545 | "'LocalUser %.100s' ", | ||
546 | filename, linenum, pw->pw_name); | ||
547 | } else if (strcasecmp(attrib, "exec") == 0) { | 563 | } else if (strcasecmp(attrib, "exec") == 0) { |
548 | if (gethostname(thishost, sizeof(thishost)) == -1) | 564 | if (gethostname(thishost, sizeof(thishost)) == -1) |
549 | fatal("gethostname: %s", strerror(errno)); | 565 | fatal("gethostname: %s", strerror(errno)); |
@@ -556,47 +572,49 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw, | |||
556 | "d", pw->pw_dir, | 572 | "d", pw->pw_dir, |
557 | "h", host, | 573 | "h", host, |
558 | "l", thishost, | 574 | "l", thishost, |
559 | "n", host_arg, | 575 | "n", original_host, |
560 | "p", portstr, | 576 | "p", portstr, |
561 | "r", ruser, | 577 | "r", ruser, |
562 | "u", pw->pw_name, | 578 | "u", pw->pw_name, |
563 | (char *)NULL); | 579 | (char *)NULL); |
564 | if (result != 1) { | 580 | if (result != 1) { |
565 | /* skip execution if prior predicate failed */ | 581 | /* skip execution if prior predicate failed */ |
566 | debug("%.200s line %d: skipped exec \"%.100s\"", | 582 | debug3("%.200s line %d: skipped exec " |
567 | filename, linenum, cmd); | 583 | "\"%.100s\"", filename, linenum, cmd); |
568 | } else { | 584 | free(cmd); |
569 | r = execute_in_shell(cmd); | 585 | continue; |
570 | if (r == -1) { | 586 | } |
571 | fatal("%.200s line %d: match exec " | 587 | r = execute_in_shell(cmd); |
572 | "'%.100s' error", filename, | 588 | if (r == -1) { |
573 | linenum, cmd); | 589 | fatal("%.200s line %d: match exec " |
574 | } else if (r == 0) { | 590 | "'%.100s' error", filename, |
575 | debug("%.200s line %d: matched " | 591 | linenum, cmd); |
576 | "'exec \"%.100s\"'", filename, | ||
577 | linenum, cmd); | ||
578 | } else { | ||
579 | debug("%.200s line %d: no match " | ||
580 | "'exec \"%.100s\"'", filename, | ||
581 | linenum, cmd); | ||
582 | result = 0; | ||
583 | } | ||
584 | } | 592 | } |
593 | criteria = xstrdup(cmd); | ||
585 | free(cmd); | 594 | free(cmd); |
595 | /* Force exit status to boolean */ | ||
596 | r = r == 0; | ||
597 | if (r == (negate ? 1 : 0)) | ||
598 | this_result = result = 0; | ||
586 | } else { | 599 | } else { |
587 | error("Unsupported Match attribute %s", attrib); | 600 | error("Unsupported Match attribute %s", attrib); |
588 | result = -1; | 601 | result = -1; |
589 | goto out; | 602 | goto out; |
590 | } | 603 | } |
604 | debug3("%.200s line %d: %smatched '%s \"%.100s\"' ", | ||
605 | filename, linenum, this_result ? "": "not ", | ||
606 | oattrib, criteria); | ||
607 | free(criteria); | ||
591 | } | 608 | } |
592 | if (attributes == 0) { | 609 | if (attributes == 0) { |
593 | error("One or more attributes required for Match"); | 610 | error("One or more attributes required for Match"); |
594 | result = -1; | 611 | result = -1; |
595 | goto out; | 612 | goto out; |
596 | } | 613 | } |
597 | debug3("match %sfound", result ? "" : "not "); | ||
598 | *condition = cp; | ||
599 | out: | 614 | out: |
615 | if (result != -1) | ||
616 | debug2("match %sfound", result ? "" : "not "); | ||
617 | *condition = cp; | ||
600 | free(host); | 618 | free(host); |
601 | return result; | 619 | return result; |
602 | } | 620 | } |
@@ -719,7 +737,8 @@ static const struct multistate multistate_canonicalizehostname[] = { | |||
719 | #define WHITESPACE " \t\r\n" | 737 | #define WHITESPACE " \t\r\n" |
720 | int | 738 | int |
721 | process_config_line(Options *options, struct passwd *pw, const char *host, | 739 | process_config_line(Options *options, struct passwd *pw, const char *host, |
722 | char *line, const char *filename, int linenum, int *activep, int userconfig) | 740 | const char *original_host, char *line, const char *filename, |
741 | int linenum, int *activep, int flags) | ||
723 | { | 742 | { |
724 | char *s, **charptr, *endofnumber, *keyword, *arg, *arg2; | 743 | char *s, **charptr, *endofnumber, *keyword, *arg, *arg2; |
725 | char **cpptr, fwdarg[256]; | 744 | char **cpptr, fwdarg[256]; |
@@ -775,7 +794,9 @@ parse_time: | |||
775 | if (!arg || *arg == '\0') | 794 | if (!arg || *arg == '\0') |
776 | fatal("%s line %d: missing time value.", | 795 | fatal("%s line %d: missing time value.", |
777 | filename, linenum); | 796 | filename, linenum); |
778 | if ((value = convtime(arg)) == -1) | 797 | if (strcmp(arg, "none") == 0) |
798 | value = -1; | ||
799 | else if ((value = convtime(arg)) == -1) | ||
779 | fatal("%s line %d: invalid time value.", | 800 | fatal("%s line %d: invalid time value.", |
780 | filename, linenum); | 801 | filename, linenum); |
781 | if (*activep && *intptr == -1) | 802 | if (*activep && *intptr == -1) |
@@ -812,7 +833,7 @@ parse_time: | |||
812 | case oForwardX11Trusted: | 833 | case oForwardX11Trusted: |
813 | intptr = &options->forward_x11_trusted; | 834 | intptr = &options->forward_x11_trusted; |
814 | goto parse_flag; | 835 | goto parse_flag; |
815 | 836 | ||
816 | case oForwardX11Timeout: | 837 | case oForwardX11Timeout: |
817 | intptr = &options->forward_x11_timeout; | 838 | intptr = &options->forward_x11_timeout; |
818 | goto parse_time; | 839 | goto parse_time; |
@@ -947,7 +968,8 @@ parse_time: | |||
947 | if (*intptr >= SSH_MAX_IDENTITY_FILES) | 968 | if (*intptr >= SSH_MAX_IDENTITY_FILES) |
948 | fatal("%.200s line %d: Too many identity files specified (max %d).", | 969 | fatal("%.200s line %d: Too many identity files specified (max %d).", |
949 | filename, linenum, SSH_MAX_IDENTITY_FILES); | 970 | filename, linenum, SSH_MAX_IDENTITY_FILES); |
950 | add_identity_file(options, NULL, arg, userconfig); | 971 | add_identity_file(options, NULL, |
972 | arg, flags & SSHCONF_USERCONF); | ||
951 | } | 973 | } |
952 | break; | 974 | break; |
953 | 975 | ||
@@ -1195,8 +1217,8 @@ parse_int: | |||
1195 | if (cmdline) | 1217 | if (cmdline) |
1196 | fatal("Host directive not supported as a command-line " | 1218 | fatal("Host directive not supported as a command-line " |
1197 | "option"); | 1219 | "option"); |
1198 | value = match_cfg_line(options, &s, pw, host, | 1220 | value = match_cfg_line(options, &s, pw, host, original_host, |
1199 | filename, linenum); | 1221 | flags & SSHCONF_POSTCANON, filename, linenum); |
1200 | if (value < 0) | 1222 | if (value < 0) |
1201 | fatal("%.200s line %d: Bad Match condition", filename, | 1223 | fatal("%.200s line %d: Bad Match condition", filename, |
1202 | linenum); | 1224 | linenum); |
@@ -1444,7 +1466,7 @@ parse_int: | |||
1444 | return 0; | 1466 | return 0; |
1445 | 1467 | ||
1446 | default: | 1468 | default: |
1447 | fatal("process_config_line: Unimplemented opcode %d", opcode); | 1469 | fatal("%s: Unimplemented opcode %d", __func__, opcode); |
1448 | } | 1470 | } |
1449 | 1471 | ||
1450 | /* Check that there is no garbage at end of line. */ | 1472 | /* Check that there is no garbage at end of line. */ |
@@ -1464,7 +1486,7 @@ parse_int: | |||
1464 | 1486 | ||
1465 | int | 1487 | int |
1466 | read_config_file(const char *filename, struct passwd *pw, const char *host, | 1488 | read_config_file(const char *filename, struct passwd *pw, const char *host, |
1467 | Options *options, int flags) | 1489 | const char *original_host, Options *options, int flags) |
1468 | { | 1490 | { |
1469 | FILE *f; | 1491 | FILE *f; |
1470 | char line[1024]; | 1492 | char line[1024]; |
@@ -1495,8 +1517,8 @@ read_config_file(const char *filename, struct passwd *pw, const char *host, | |||
1495 | while (fgets(line, sizeof(line), f)) { | 1517 | while (fgets(line, sizeof(line), f)) { |
1496 | /* Update line number counter. */ | 1518 | /* Update line number counter. */ |
1497 | linenum++; | 1519 | linenum++; |
1498 | if (process_config_line(options, pw, host, line, filename, | 1520 | if (process_config_line(options, pw, host, original_host, |
1499 | linenum, &active, flags & SSHCONF_USERCONF) != 0) | 1521 | line, filename, linenum, &active, flags) != 0) |
1500 | bad_options++; | 1522 | bad_options++; |
1501 | } | 1523 | } |
1502 | fclose(f); | 1524 | fclose(f); |
@@ -2009,3 +2031,295 @@ parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remo | |||
2009 | fwd->listen_path = NULL; | 2031 | fwd->listen_path = NULL; |
2010 | return (0); | 2032 | return (0); |
2011 | } | 2033 | } |
2034 | |||
2035 | /* XXX the following is a near-vebatim copy from servconf.c; refactor */ | ||
2036 | static const char * | ||
2037 | fmt_multistate_int(int val, const struct multistate *m) | ||
2038 | { | ||
2039 | u_int i; | ||
2040 | |||
2041 | for (i = 0; m[i].key != NULL; i++) { | ||
2042 | if (m[i].value == val) | ||
2043 | return m[i].key; | ||
2044 | } | ||
2045 | return "UNKNOWN"; | ||
2046 | } | ||
2047 | |||
2048 | static const char * | ||
2049 | fmt_intarg(OpCodes code, int val) | ||
2050 | { | ||
2051 | if (val == -1) | ||
2052 | return "unset"; | ||
2053 | switch (code) { | ||
2054 | case oAddressFamily: | ||
2055 | return fmt_multistate_int(val, multistate_addressfamily); | ||
2056 | case oVerifyHostKeyDNS: | ||
2057 | case oStrictHostKeyChecking: | ||
2058 | return fmt_multistate_int(val, multistate_yesnoask); | ||
2059 | case oControlMaster: | ||
2060 | return fmt_multistate_int(val, multistate_controlmaster); | ||
2061 | case oTunnel: | ||
2062 | return fmt_multistate_int(val, multistate_tunnel); | ||
2063 | case oRequestTTY: | ||
2064 | return fmt_multistate_int(val, multistate_requesttty); | ||
2065 | case oCanonicalizeHostname: | ||
2066 | return fmt_multistate_int(val, multistate_canonicalizehostname); | ||
2067 | case oProtocol: | ||
2068 | switch (val) { | ||
2069 | case SSH_PROTO_1: | ||
2070 | return "1"; | ||
2071 | case SSH_PROTO_2: | ||
2072 | return "2"; | ||
2073 | case (SSH_PROTO_1|SSH_PROTO_2): | ||
2074 | return "2,1"; | ||
2075 | default: | ||
2076 | return "UNKNOWN"; | ||
2077 | } | ||
2078 | default: | ||
2079 | switch (val) { | ||
2080 | case 0: | ||
2081 | return "no"; | ||
2082 | case 1: | ||
2083 | return "yes"; | ||
2084 | default: | ||
2085 | return "UNKNOWN"; | ||
2086 | } | ||
2087 | } | ||
2088 | } | ||
2089 | |||
2090 | static const char * | ||
2091 | lookup_opcode_name(OpCodes code) | ||
2092 | { | ||
2093 | u_int i; | ||
2094 | |||
2095 | for (i = 0; keywords[i].name != NULL; i++) | ||
2096 | if (keywords[i].opcode == code) | ||
2097 | return(keywords[i].name); | ||
2098 | return "UNKNOWN"; | ||
2099 | } | ||
2100 | |||
2101 | static void | ||
2102 | dump_cfg_int(OpCodes code, int val) | ||
2103 | { | ||
2104 | printf("%s %d\n", lookup_opcode_name(code), val); | ||
2105 | } | ||
2106 | |||
2107 | static void | ||
2108 | dump_cfg_fmtint(OpCodes code, int val) | ||
2109 | { | ||
2110 | printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val)); | ||
2111 | } | ||
2112 | |||
2113 | static void | ||
2114 | dump_cfg_string(OpCodes code, const char *val) | ||
2115 | { | ||
2116 | if (val == NULL) | ||
2117 | return; | ||
2118 | printf("%s %s\n", lookup_opcode_name(code), val); | ||
2119 | } | ||
2120 | |||
2121 | static void | ||
2122 | dump_cfg_strarray(OpCodes code, u_int count, char **vals) | ||
2123 | { | ||
2124 | u_int i; | ||
2125 | |||
2126 | for (i = 0; i < count; i++) | ||
2127 | printf("%s %s\n", lookup_opcode_name(code), vals[i]); | ||
2128 | } | ||
2129 | |||
2130 | static void | ||
2131 | dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals) | ||
2132 | { | ||
2133 | u_int i; | ||
2134 | |||
2135 | printf("%s", lookup_opcode_name(code)); | ||
2136 | for (i = 0; i < count; i++) | ||
2137 | printf(" %s", vals[i]); | ||
2138 | printf("\n"); | ||
2139 | } | ||
2140 | |||
2141 | static void | ||
2142 | dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds) | ||
2143 | { | ||
2144 | const struct Forward *fwd; | ||
2145 | u_int i; | ||
2146 | |||
2147 | /* oDynamicForward */ | ||
2148 | for (i = 0; i < count; i++) { | ||
2149 | fwd = &fwds[i]; | ||
2150 | if (code == oDynamicForward && | ||
2151 | strcmp(fwd->connect_host, "socks") != 0) | ||
2152 | continue; | ||
2153 | if (code == oLocalForward && | ||
2154 | strcmp(fwd->connect_host, "socks") == 0) | ||
2155 | continue; | ||
2156 | printf("%s", lookup_opcode_name(code)); | ||
2157 | if (fwd->listen_port == PORT_STREAMLOCAL) | ||
2158 | printf(" %s", fwd->listen_path); | ||
2159 | else if (fwd->listen_host == NULL) | ||
2160 | printf(" %d", fwd->listen_port); | ||
2161 | else { | ||
2162 | printf(" [%s]:%d", | ||
2163 | fwd->listen_host, fwd->listen_port); | ||
2164 | } | ||
2165 | if (code != oDynamicForward) { | ||
2166 | if (fwd->connect_port == PORT_STREAMLOCAL) | ||
2167 | printf(" %s", fwd->connect_path); | ||
2168 | else if (fwd->connect_host == NULL) | ||
2169 | printf(" %d", fwd->connect_port); | ||
2170 | else { | ||
2171 | printf(" [%s]:%d", | ||
2172 | fwd->connect_host, fwd->connect_port); | ||
2173 | } | ||
2174 | } | ||
2175 | printf("\n"); | ||
2176 | } | ||
2177 | } | ||
2178 | |||
2179 | void | ||
2180 | dump_client_config(Options *o, const char *host) | ||
2181 | { | ||
2182 | int i; | ||
2183 | char vbuf[5]; | ||
2184 | |||
2185 | /* Most interesting options first: user, host, port */ | ||
2186 | dump_cfg_string(oUser, o->user); | ||
2187 | dump_cfg_string(oHostName, host); | ||
2188 | dump_cfg_int(oPort, o->port); | ||
2189 | |||
2190 | /* Flag options */ | ||
2191 | dump_cfg_fmtint(oAddressFamily, o->address_family); | ||
2192 | dump_cfg_fmtint(oBatchMode, o->batch_mode); | ||
2193 | dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local); | ||
2194 | dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname); | ||
2195 | dump_cfg_fmtint(oChallengeResponseAuthentication, o->challenge_response_authentication); | ||
2196 | dump_cfg_fmtint(oCheckHostIP, o->check_host_ip); | ||
2197 | dump_cfg_fmtint(oCompression, o->compression); | ||
2198 | dump_cfg_fmtint(oControlMaster, o->control_master); | ||
2199 | dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign); | ||
2200 | dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure); | ||
2201 | dump_cfg_fmtint(oForwardAgent, o->forward_agent); | ||
2202 | dump_cfg_fmtint(oForwardX11, o->forward_x11); | ||
2203 | dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted); | ||
2204 | dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports); | ||
2205 | #ifdef GSSAPI | ||
2206 | dump_cfg_fmtint(oGssAuthentication, o->gss_authentication); | ||
2207 | dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds); | ||
2208 | #endif /* GSSAPI */ | ||
2209 | dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts); | ||
2210 | dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication); | ||
2211 | dump_cfg_fmtint(oIdentitiesOnly, o->identities_only); | ||
2212 | dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication); | ||
2213 | dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost); | ||
2214 | dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication); | ||
2215 | dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command); | ||
2216 | dump_cfg_fmtint(oProtocol, o->protocol); | ||
2217 | dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass); | ||
2218 | dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication); | ||
2219 | dump_cfg_fmtint(oRequestTTY, o->request_tty); | ||
2220 | dump_cfg_fmtint(oRhostsRSAAuthentication, o->rhosts_rsa_authentication); | ||
2221 | dump_cfg_fmtint(oRSAAuthentication, o->rsa_authentication); | ||
2222 | dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); | ||
2223 | dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking); | ||
2224 | dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive); | ||
2225 | dump_cfg_fmtint(oTunnel, o->tun_open); | ||
2226 | dump_cfg_fmtint(oUsePrivilegedPort, o->use_privileged_port); | ||
2227 | dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns); | ||
2228 | dump_cfg_fmtint(oVisualHostKey, o->visual_host_key); | ||
2229 | |||
2230 | /* Integer options */ | ||
2231 | dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots); | ||
2232 | dump_cfg_int(oCompressionLevel, o->compression_level); | ||
2233 | dump_cfg_int(oConnectionAttempts, o->connection_attempts); | ||
2234 | dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout); | ||
2235 | dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts); | ||
2236 | dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max); | ||
2237 | dump_cfg_int(oServerAliveInterval, o->server_alive_interval); | ||
2238 | |||
2239 | /* String options */ | ||
2240 | dump_cfg_string(oBindAddress, o->bind_address); | ||
2241 | dump_cfg_string(oCiphers, o->ciphers ? o->ciphers : KEX_CLIENT_ENCRYPT); | ||
2242 | dump_cfg_string(oControlPath, o->control_path); | ||
2243 | dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms ? o->hostkeyalgorithms : KEX_DEFAULT_PK_ALG); | ||
2244 | dump_cfg_string(oHostKeyAlias, o->host_key_alias); | ||
2245 | dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices); | ||
2246 | dump_cfg_string(oKexAlgorithms, o->kex_algorithms ? o->kex_algorithms : KEX_CLIENT_KEX); | ||
2247 | dump_cfg_string(oLocalCommand, o->local_command); | ||
2248 | dump_cfg_string(oLogLevel, log_level_name(o->log_level)); | ||
2249 | dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC); | ||
2250 | dump_cfg_string(oPKCS11Provider, o->pkcs11_provider); | ||
2251 | dump_cfg_string(oPreferredAuthentications, o->preferred_authentications); | ||
2252 | dump_cfg_string(oProxyCommand, o->proxy_command); | ||
2253 | dump_cfg_string(oXAuthLocation, o->xauth_location); | ||
2254 | |||
2255 | dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards); | ||
2256 | dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards); | ||
2257 | dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards); | ||
2258 | |||
2259 | /* String array options */ | ||
2260 | dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files); | ||
2261 | dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains); | ||
2262 | dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles); | ||
2263 | dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles); | ||
2264 | dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env); | ||
2265 | |||
2266 | /* Special cases */ | ||
2267 | |||
2268 | /* oConnectTimeout */ | ||
2269 | if (o->connection_timeout == -1) | ||
2270 | printf("connecttimeout none\n"); | ||
2271 | else | ||
2272 | dump_cfg_int(oConnectTimeout, o->connection_timeout); | ||
2273 | |||
2274 | /* oTunnelDevice */ | ||
2275 | printf("tunneldevice"); | ||
2276 | if (o->tun_local == SSH_TUNID_ANY) | ||
2277 | printf(" any"); | ||
2278 | else | ||
2279 | printf(" %d", o->tun_local); | ||
2280 | if (o->tun_remote == SSH_TUNID_ANY) | ||
2281 | printf(":any"); | ||
2282 | else | ||
2283 | printf(":%d", o->tun_remote); | ||
2284 | printf("\n"); | ||
2285 | |||
2286 | /* oCanonicalizePermittedCNAMEs */ | ||
2287 | if ( o->num_permitted_cnames > 0) { | ||
2288 | printf("canonicalizePermittedcnames"); | ||
2289 | for (i = 0; i < o->num_permitted_cnames; i++) { | ||
2290 | printf(" %s:%s", o->permitted_cnames[i].source_list, | ||
2291 | o->permitted_cnames[i].target_list); | ||
2292 | } | ||
2293 | printf("\n"); | ||
2294 | } | ||
2295 | |||
2296 | /* oCipher */ | ||
2297 | if (o->cipher != SSH_CIPHER_NOT_SET) | ||
2298 | printf("Cipher %s\n", cipher_name(o->cipher)); | ||
2299 | |||
2300 | /* oControlPersist */ | ||
2301 | if (o->control_persist == 0 || o->control_persist_timeout == 0) | ||
2302 | dump_cfg_fmtint(oControlPersist, o->control_persist); | ||
2303 | else | ||
2304 | dump_cfg_int(oControlPersist, o->control_persist_timeout); | ||
2305 | |||
2306 | /* oEscapeChar */ | ||
2307 | if (o->escape_char == SSH_ESCAPECHAR_NONE) | ||
2308 | printf("escapechar none\n"); | ||
2309 | else { | ||
2310 | vis(vbuf, o->escape_char, VIS_WHITE, 0); | ||
2311 | printf("escapechar %s\n", vbuf); | ||
2312 | } | ||
2313 | |||
2314 | /* oIPQoS */ | ||
2315 | printf("ipqos %s ", iptos2str(o->ip_qos_interactive)); | ||
2316 | printf("%s\n", iptos2str(o->ip_qos_bulk)); | ||
2317 | |||
2318 | /* oRekeyLimit */ | ||
2319 | printf("rekeylimit %lld %d\n", | ||
2320 | (long long)o->rekey_limit, o->rekey_interval); | ||
2321 | |||
2322 | /* oStreamLocalBindMask */ | ||
2323 | printf("streamlocalbindmask 0%o\n", | ||
2324 | o->fwd_opts.streamlocal_bind_mask); | ||
2325 | } | ||
diff --git a/readconf.h b/readconf.h index 0b9cb777a..7b58d01f3 100644 --- a/readconf.h +++ b/readconf.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: readconf.h,v 1.102 2014/07/15 15:54:14 millert Exp $ */ | 1 | /* $OpenBSD: readconf.h,v 1.103 2014/10/08 22:20:25 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -164,17 +164,19 @@ typedef struct { | |||
164 | 164 | ||
165 | #define SSHCONF_CHECKPERM 1 /* check permissions on config file */ | 165 | #define SSHCONF_CHECKPERM 1 /* check permissions on config file */ |
166 | #define SSHCONF_USERCONF 2 /* user provided config file not system */ | 166 | #define SSHCONF_USERCONF 2 /* user provided config file not system */ |
167 | #define SSHCONF_POSTCANON 4 /* After hostname canonicalisation */ | ||
167 | 168 | ||
168 | void initialize_options(Options *); | 169 | void initialize_options(Options *); |
169 | void fill_default_options(Options *); | 170 | void fill_default_options(Options *); |
170 | void fill_default_options_for_canonicalization(Options *); | 171 | void fill_default_options_for_canonicalization(Options *); |
171 | int process_config_line(Options *, struct passwd *, const char *, char *, | 172 | int process_config_line(Options *, struct passwd *, const char *, |
172 | const char *, int, int *, int); | 173 | const char *, char *, const char *, int, int *, int); |
173 | int read_config_file(const char *, struct passwd *, const char *, | 174 | int read_config_file(const char *, struct passwd *, const char *, |
174 | Options *, int); | 175 | const char *, Options *, int); |
175 | int parse_forward(struct Forward *, const char *, int, int); | 176 | int parse_forward(struct Forward *, const char *, int, int); |
176 | int default_ssh_port(void); | 177 | int default_ssh_port(void); |
177 | int option_clear_or_none(const char *); | 178 | int option_clear_or_none(const char *); |
179 | void dump_client_config(Options *o, const char *host); | ||
178 | 180 | ||
179 | void add_local_forward(Options *, const struct Forward *); | 181 | void add_local_forward(Options *, const struct Forward *); |
180 | void add_remote_forward(Options *, const struct Forward *); | 182 | void add_remote_forward(Options *, const struct Forward *); |
diff --git a/ssh-keysign.c b/ssh-keysign.c index d95bb7d9d..6b73319e0 100644 --- a/ssh-keysign.c +++ b/ssh-keysign.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-keysign.c,v 1.42 2014/04/29 18:01:49 markus Exp $ */ | 1 | /* $OpenBSD: ssh-keysign.c,v 1.43 2014/10/08 22:20:25 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2002 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2002 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -187,7 +187,7 @@ main(int argc, char **argv) | |||
187 | 187 | ||
188 | /* verify that ssh-keysign is enabled by the admin */ | 188 | /* verify that ssh-keysign is enabled by the admin */ |
189 | initialize_options(&options); | 189 | initialize_options(&options); |
190 | (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, "", &options, 0); | 190 | (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, "", "", &options, 0); |
191 | fill_default_options(&options); | 191 | fill_default_options(&options); |
192 | if (options.enable_ssh_keysign != 1) | 192 | if (options.enable_ssh_keysign != 1) |
193 | fatal("ssh-keysign not enabled in %s", | 193 | fatal("ssh-keysign not enabled in %s", |
@@ -33,8 +33,8 @@ | |||
33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
35 | .\" | 35 | .\" |
36 | .\" $OpenBSD: ssh.1,v 1.349 2014/08/30 15:33:50 sobrado Exp $ | 36 | .\" $OpenBSD: ssh.1,v 1.350 2014/10/08 22:20:25 djm Exp $ |
37 | .Dd $Mdocdate: August 30 2014 $ | 37 | .Dd $Mdocdate: October 8 2014 $ |
38 | .Dt SSH 1 | 38 | .Dt SSH 1 |
39 | .Os | 39 | .Os |
40 | .Sh NAME | 40 | .Sh NAME |
@@ -43,7 +43,7 @@ | |||
43 | .Sh SYNOPSIS | 43 | .Sh SYNOPSIS |
44 | .Nm ssh | 44 | .Nm ssh |
45 | .Bk -words | 45 | .Bk -words |
46 | .Op Fl 1246AaCfgKkMNnqsTtVvXxYy | 46 | .Op Fl 1246AaCfgGKkMNnqsTtVvXxYy |
47 | .Op Fl b Ar bind_address | 47 | .Op Fl b Ar bind_address |
48 | .Op Fl c Ar cipher_spec | 48 | .Op Fl c Ar cipher_spec |
49 | .Op Fl D Oo Ar bind_address : Oc Ns Ar port | 49 | .Op Fl D Oo Ar bind_address : Oc Ns Ar port |
@@ -251,6 +251,14 @@ then a client started with | |||
251 | .Fl f | 251 | .Fl f |
252 | will wait for all remote port forwards to be successfully established | 252 | will wait for all remote port forwards to be successfully established |
253 | before placing itself in the background. | 253 | before placing itself in the background. |
254 | .It Fl G | ||
255 | Causes | ||
256 | .Nm | ||
257 | to print its configuration after evaluating | ||
258 | .Cm Host | ||
259 | and | ||
260 | .Cm Match | ||
261 | blocks and exit. | ||
254 | .It Fl g | 262 | .It Fl g |
255 | Allows remote hosts to connect to local forwarded ports. | 263 | Allows remote hosts to connect to local forwarded ports. |
256 | If used on a multiplexed connection, then this option must be specified | 264 | If used on a multiplexed connection, then this option must be specified |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh.c,v 1.407 2014/07/17 07:22:19 djm Exp $ */ | 1 | /* $OpenBSD: ssh.c,v 1.408 2014/10/08 22:20:25 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 |
@@ -384,27 +384,49 @@ resolve_canonicalize(char **hostp, int port) | |||
384 | * file if the user specifies a config file on the command line. | 384 | * file if the user specifies a config file on the command line. |
385 | */ | 385 | */ |
386 | static void | 386 | static void |
387 | process_config_files(struct passwd *pw) | 387 | process_config_files(const char *host_arg, struct passwd *pw, int post_canon) |
388 | { | 388 | { |
389 | char buf[MAXPATHLEN]; | 389 | char buf[MAXPATHLEN]; |
390 | int r; | 390 | int r; |
391 | 391 | ||
392 | if (config != NULL) { | 392 | if (config != NULL) { |
393 | if (strcasecmp(config, "none") != 0 && | 393 | if (strcasecmp(config, "none") != 0 && |
394 | !read_config_file(config, pw, host, &options, | 394 | !read_config_file(config, pw, host, host_arg, &options, |
395 | SSHCONF_USERCONF)) | 395 | SSHCONF_USERCONF | (post_canon ? SSHCONF_POSTCANON : 0))) |
396 | fatal("Can't open user config file %.100s: " | 396 | fatal("Can't open user config file %.100s: " |
397 | "%.100s", config, strerror(errno)); | 397 | "%.100s", config, strerror(errno)); |
398 | } else { | 398 | } else { |
399 | r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, | 399 | r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, |
400 | _PATH_SSH_USER_CONFFILE); | 400 | _PATH_SSH_USER_CONFFILE); |
401 | if (r > 0 && (size_t)r < sizeof(buf)) | 401 | if (r > 0 && (size_t)r < sizeof(buf)) |
402 | (void)read_config_file(buf, pw, host, &options, | 402 | (void)read_config_file(buf, pw, host, host_arg, |
403 | SSHCONF_CHECKPERM|SSHCONF_USERCONF); | 403 | &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | |
404 | (post_canon ? SSHCONF_POSTCANON : 0)); | ||
404 | 405 | ||
405 | /* Read systemwide configuration file after user config. */ | 406 | /* Read systemwide configuration file after user config. */ |
406 | (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, host, | 407 | (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, |
407 | &options, 0); | 408 | host, host_arg, &options, |
409 | post_canon ? SSHCONF_POSTCANON : 0); | ||
410 | } | ||
411 | } | ||
412 | |||
413 | /* Rewrite the port number in an addrinfo list of addresses */ | ||
414 | static void | ||
415 | set_addrinfo_port(struct addrinfo *addrs, int port) | ||
416 | { | ||
417 | struct addrinfo *addr; | ||
418 | |||
419 | for (addr = addrs; addr != NULL; addr = addr->ai_next) { | ||
420 | switch (addr->ai_family) { | ||
421 | case AF_INET: | ||
422 | ((struct sockaddr_in *)addr->ai_addr)-> | ||
423 | sin_port = htons(port); | ||
424 | break; | ||
425 | case AF_INET6: | ||
426 | ((struct sockaddr_in6 *)addr->ai_addr)-> | ||
427 | sin6_port = htons(port); | ||
428 | break; | ||
429 | } | ||
408 | } | 430 | } |
409 | } | 431 | } |
410 | 432 | ||
@@ -414,7 +436,7 @@ process_config_files(struct passwd *pw) | |||
414 | int | 436 | int |
415 | main(int ac, char **av) | 437 | main(int ac, char **av) |
416 | { | 438 | { |
417 | int i, r, opt, exit_status, use_syslog; | 439 | int i, r, opt, exit_status, use_syslog, config_test = 0; |
418 | char *p, *cp, *line, *argv0, buf[MAXPATHLEN], *host_arg, *logfile; | 440 | char *p, *cp, *line, *argv0, buf[MAXPATHLEN], *host_arg, *logfile; |
419 | char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; | 441 | char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; |
420 | char cname[NI_MAXHOST]; | 442 | char cname[NI_MAXHOST]; |
@@ -507,7 +529,7 @@ main(int ac, char **av) | |||
507 | 529 | ||
508 | again: | 530 | again: |
509 | while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" | 531 | while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" |
510 | "ACD:E:F:I:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) { | 532 | "ACD:E:F:GI:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) { |
511 | switch (opt) { | 533 | switch (opt) { |
512 | case '1': | 534 | case '1': |
513 | options.protocol = SSH_PROTO_1; | 535 | options.protocol = SSH_PROTO_1; |
@@ -540,6 +562,9 @@ main(int ac, char **av) | |||
540 | case 'E': | 562 | case 'E': |
541 | logfile = xstrdup(optarg); | 563 | logfile = xstrdup(optarg); |
542 | break; | 564 | break; |
565 | case 'G': | ||
566 | config_test = 1; | ||
567 | break; | ||
543 | case 'Y': | 568 | case 'Y': |
544 | options.forward_x11 = 1; | 569 | options.forward_x11 = 1; |
545 | options.forward_x11_trusted = 1; | 570 | options.forward_x11_trusted = 1; |
@@ -788,9 +813,9 @@ main(int ac, char **av) | |||
788 | break; | 813 | break; |
789 | case 'o': | 814 | case 'o': |
790 | line = xstrdup(optarg); | 815 | line = xstrdup(optarg); |
791 | if (process_config_line(&options, pw, host ? host : "", | 816 | if (process_config_line(&options, pw, |
792 | line, "command-line", 0, NULL, SSHCONF_USERCONF) | 817 | host ? host : "", host ? host : "", line, |
793 | != 0) | 818 | "command-line", 0, NULL, SSHCONF_USERCONF) != 0) |
794 | exit(255); | 819 | exit(255); |
795 | free(line); | 820 | free(line); |
796 | break; | 821 | break; |
@@ -899,7 +924,7 @@ main(int ac, char **av) | |||
899 | ); | 924 | ); |
900 | 925 | ||
901 | /* Parse the configuration files */ | 926 | /* Parse the configuration files */ |
902 | process_config_files(pw); | 927 | process_config_files(host_arg, pw, 0); |
903 | 928 | ||
904 | /* Hostname canonicalisation needs a few options filled. */ | 929 | /* Hostname canonicalisation needs a few options filled. */ |
905 | fill_default_options_for_canonicalization(&options); | 930 | fill_default_options_for_canonicalization(&options); |
@@ -911,6 +936,8 @@ main(int ac, char **av) | |||
911 | "h", host, (char *)NULL); | 936 | "h", host, (char *)NULL); |
912 | free(host); | 937 | free(host); |
913 | host = cp; | 938 | host = cp; |
939 | free(options.hostname); | ||
940 | options.hostname = xstrdup(host); | ||
914 | } | 941 | } |
915 | 942 | ||
916 | /* If canonicalization requested then try to apply it */ | 943 | /* If canonicalization requested then try to apply it */ |
@@ -945,12 +972,22 @@ main(int ac, char **av) | |||
945 | } | 972 | } |
946 | 973 | ||
947 | /* | 974 | /* |
948 | * If the target hostname has changed as a result of canonicalisation | 975 | * If canonicalisation is enabled then re-parse the configuration |
949 | * then re-parse the configuration files as new stanzas may match. | 976 | * files as new stanzas may match. |
950 | */ | 977 | */ |
951 | if (strcasecmp(host_arg, host) != 0) { | 978 | if (options.canonicalize_hostname != 0) { |
952 | debug("Hostname has changed; re-reading configuration"); | 979 | debug("Re-reading configuration after hostname " |
953 | process_config_files(pw); | 980 | "canonicalisation"); |
981 | free(options.hostname); | ||
982 | options.hostname = xstrdup(host); | ||
983 | process_config_files(host_arg, pw, 1); | ||
984 | /* | ||
985 | * Address resolution happens early with canonicalisation | ||
986 | * enabled and the port number may have changed since, so | ||
987 | * reset it in address list | ||
988 | */ | ||
989 | if (addrs != NULL && options.port > 0) | ||
990 | set_addrinfo_port(addrs, options.port); | ||
954 | } | 991 | } |
955 | 992 | ||
956 | /* Fill configuration defaults. */ | 993 | /* Fill configuration defaults. */ |
@@ -1052,6 +1089,11 @@ main(int ac, char **av) | |||
1052 | } | 1089 | } |
1053 | free(conn_hash_hex); | 1090 | free(conn_hash_hex); |
1054 | 1091 | ||
1092 | if (config_test) { | ||
1093 | dump_client_config(&options, host); | ||
1094 | exit(0); | ||
1095 | } | ||
1096 | |||
1055 | if (muxclient_command != 0 && options.control_path == NULL) | 1097 | if (muxclient_command != 0 && options.control_path == NULL) |
1056 | fatal("No ControlPath specified for \"-O\" command"); | 1098 | fatal("No ControlPath specified for \"-O\" command"); |
1057 | if (options.control_path != NULL) | 1099 | if (options.control_path != NULL) |
diff --git a/ssh_config.5 b/ssh_config.5 index 4396aa907..b702e323f 100644 --- a/ssh_config.5 +++ b/ssh_config.5 | |||
@@ -33,8 +33,8 @@ | |||
33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
35 | .\" | 35 | .\" |
36 | .\" $OpenBSD: ssh_config.5,v 1.192 2014/08/30 15:33:50 sobrado Exp $ | 36 | .\" $OpenBSD: ssh_config.5,v 1.193 2014/10/08 22:20:25 djm Exp $ |
37 | .Dd $Mdocdate: August 30 2014 $ | 37 | .Dd $Mdocdate: October 8 2014 $ |
38 | .Dt SSH_CONFIG 5 | 38 | .Dt SSH_CONFIG 5 |
39 | .Os | 39 | .Os |
40 | .Sh NAME | 40 | .Sh NAME |
@@ -65,7 +65,10 @@ The configuration files contain sections separated by | |||
65 | .Dq Host | 65 | .Dq Host |
66 | specifications, and that section is only applied for hosts that | 66 | specifications, and that section is only applied for hosts that |
67 | match one of the patterns given in the specification. | 67 | match one of the patterns given in the specification. |
68 | The matched host name is the one given on the command line. | 68 | The matched host name is usually the one given on the command line |
69 | (see the | ||
70 | .Cm CanonicalizeHostname | ||
71 | option for exceptions.) | ||
69 | .Pp | 72 | .Pp |
70 | Since the first obtained value for each parameter is used, more | 73 | Since the first obtained value for each parameter is used, more |
71 | host-specific declarations should be given near the beginning of the | 74 | host-specific declarations should be given near the beginning of the |
@@ -109,10 +112,12 @@ A single | |||
109 | .Ql * | 112 | .Ql * |
110 | as a pattern can be used to provide global | 113 | as a pattern can be used to provide global |
111 | defaults for all hosts. | 114 | defaults for all hosts. |
112 | The host is the | 115 | The host is usually the |
113 | .Ar hostname | 116 | .Ar hostname |
114 | argument given on the command line (i.e. the name is not converted to | 117 | argument given on the command line |
115 | a canonicalized host name before matching). | 118 | (see the |
119 | .Cm CanonicalizeHostname | ||
120 | option for exceptions.) | ||
116 | .Pp | 121 | .Pp |
117 | A pattern entry may be negated by prefixing it with an exclamation mark | 122 | A pattern entry may be negated by prefixing it with an exclamation mark |
118 | .Pq Sq !\& . | 123 | .Pq Sq !\& . |
@@ -134,19 +139,40 @@ or | |||
134 | keyword) to be used only when the conditions following the | 139 | keyword) to be used only when the conditions following the |
135 | .Cm Match | 140 | .Cm Match |
136 | keyword are satisfied. | 141 | keyword are satisfied. |
137 | Match conditions are specified using one or more keyword/criteria pairs | 142 | Match conditions are specified using one or more critera |
138 | or the single token | 143 | or the single token |
139 | .Cm all | 144 | .Cm all |
140 | which matches all criteria. | 145 | which always matches. |
141 | The available keywords are: | 146 | The available criteria keywords are: |
147 | .Cm canonical , | ||
142 | .Cm exec , | 148 | .Cm exec , |
143 | .Cm host , | 149 | .Cm host , |
144 | .Cm originalhost , | 150 | .Cm originalhost , |
145 | .Cm user , | 151 | .Cm user , |
146 | and | 152 | and |
147 | .Cm localuser . | 153 | .Cm localuser . |
154 | The | ||
155 | .Cm all | ||
156 | criteria must appear alone or immediately after | ||
157 | .Cm canonical. | ||
158 | Other criteria may be combined arbitrarily. | ||
159 | All criteria but | ||
160 | .Cm all | ||
161 | and | ||
162 | .Cm canonical | ||
163 | require an argument. | ||
164 | Criteria may be negated by prepending an exclamation mark | ||
165 | .Pq Sq !\& . | ||
148 | .Pp | 166 | .Pp |
149 | The | 167 | The |
168 | .Cm canonical | ||
169 | keywork matches only when the configuration file is being re-parsed | ||
170 | after hostname canonicalization (see the | ||
171 | .Cm CanonicalizeHostname | ||
172 | option.) | ||
173 | This may be useful to specify conditions that work with canonical host | ||
174 | names only. | ||
175 | The | ||
150 | .Cm exec | 176 | .Cm exec |
151 | keyword executes the specified command under the user's shell. | 177 | keyword executes the specified command under the user's shell. |
152 | If the command returns a zero exit status then the condition is considered true. | 178 | If the command returns a zero exit status then the condition is considered true. |
@@ -179,7 +205,9 @@ The criteria for the | |||
179 | keyword are matched against the target hostname, after any substitution | 205 | keyword are matched against the target hostname, after any substitution |
180 | by the | 206 | by the |
181 | .Cm Hostname | 207 | .Cm Hostname |
182 | option. | 208 | or |
209 | .Cm CanonicalizeHostname | ||
210 | options. | ||
183 | The | 211 | The |
184 | .Cm originalhost | 212 | .Cm originalhost |
185 | keyword matches against the hostname as it was specified on the command-line. | 213 | keyword matches against the hostname as it was specified on the command-line. |
@@ -264,10 +292,11 @@ is set to | |||
264 | .Dq always , | 292 | .Dq always , |
265 | then canonicalization is applied to proxied connections too. | 293 | then canonicalization is applied to proxied connections too. |
266 | .Pp | 294 | .Pp |
267 | If this option is enabled and canonicalisation results in the target hostname | 295 | If this option is enabled, then the configuration files are processed |
268 | changing, then the configuration files are processed again using the new | 296 | again using the new target name to pick up any new configuration in matching |
269 | target name to pick up any new configuration in matching | ||
270 | .Cm Host | 297 | .Cm Host |
298 | and | ||
299 | .Cm Match | ||
271 | stanzas. | 300 | stanzas. |
272 | .It Cm CanonicalizeMaxDots | 301 | .It Cm CanonicalizeMaxDots |
273 | Specifies the maximum number of dot characters in a hostname before | 302 | Specifies the maximum number of dot characters in a hostname before |