diff options
Diffstat (limited to 'servconf.c')
-rw-r--r-- | servconf.c | 561 |
1 files changed, 359 insertions, 202 deletions
diff --git a/servconf.c b/servconf.c index 9daa182c0..0a8f6fd62 100644 --- a/servconf.c +++ b/servconf.c | |||
@@ -1,5 +1,5 @@ | |||
1 | 1 | ||
2 | /* $OpenBSD: servconf.c,v 1.313 2017/10/04 18:49:30 djm Exp $ */ | 2 | /* $OpenBSD: servconf.c,v 1.326 2018/03/01 20:32:16 markus Exp $ */ |
3 | /* | 3 | /* |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
5 | * All rights reserved | 5 | * All rights reserved |
@@ -15,10 +15,16 @@ | |||
15 | 15 | ||
16 | #include <sys/types.h> | 16 | #include <sys/types.h> |
17 | #include <sys/socket.h> | 17 | #include <sys/socket.h> |
18 | #ifdef HAVE_SYS_SYSCTL_H | ||
19 | #include <sys/sysctl.h> | ||
20 | #endif | ||
18 | 21 | ||
19 | #include <netinet/in.h> | 22 | #include <netinet/in.h> |
20 | #include <netinet/in_systm.h> | 23 | #include <netinet/in_systm.h> |
21 | #include <netinet/ip.h> | 24 | #include <netinet/ip.h> |
25 | #ifdef HAVE_NET_ROUTE_H | ||
26 | #include <net/route.h> | ||
27 | #endif | ||
22 | 28 | ||
23 | #include <ctype.h> | 29 | #include <ctype.h> |
24 | #include <netdb.h> | 30 | #include <netdb.h> |
@@ -58,8 +64,10 @@ | |||
58 | #include "myproposal.h" | 64 | #include "myproposal.h" |
59 | #include "digest.h" | 65 | #include "digest.h" |
60 | 66 | ||
61 | static void add_listen_addr(ServerOptions *, char *, int); | 67 | static void add_listen_addr(ServerOptions *, const char *, |
62 | static void add_one_listen_addr(ServerOptions *, char *, int); | 68 | const char *, int); |
69 | static void add_one_listen_addr(ServerOptions *, const char *, | ||
70 | const char *, int); | ||
63 | 71 | ||
64 | /* Use of privilege separation or not */ | 72 | /* Use of privilege separation or not */ |
65 | extern int use_privsep; | 73 | extern int use_privsep; |
@@ -81,7 +89,9 @@ initialize_server_options(ServerOptions *options) | |||
81 | options->queued_listen_addrs = NULL; | 89 | options->queued_listen_addrs = NULL; |
82 | options->num_queued_listens = 0; | 90 | options->num_queued_listens = 0; |
83 | options->listen_addrs = NULL; | 91 | options->listen_addrs = NULL; |
92 | options->num_listen_addrs = 0; | ||
84 | options->address_family = -1; | 93 | options->address_family = -1; |
94 | options->routing_domain = NULL; | ||
85 | options->num_host_key_files = 0; | 95 | options->num_host_key_files = 0; |
86 | options->num_host_cert_files = 0; | 96 | options->num_host_cert_files = 0; |
87 | options->host_key_agent = NULL; | 97 | options->host_key_agent = NULL; |
@@ -191,10 +201,45 @@ assemble_algorithms(ServerOptions *o) | |||
191 | fatal("kex_assemble_names failed"); | 201 | fatal("kex_assemble_names failed"); |
192 | } | 202 | } |
193 | 203 | ||
204 | static void | ||
205 | array_append(const char *file, const int line, const char *directive, | ||
206 | char ***array, u_int *lp, const char *s) | ||
207 | { | ||
208 | |||
209 | if (*lp >= INT_MAX) | ||
210 | fatal("%s line %d: Too many %s entries", file, line, directive); | ||
211 | |||
212 | *array = xrecallocarray(*array, *lp, *lp + 1, sizeof(**array)); | ||
213 | (*array)[*lp] = xstrdup(s); | ||
214 | (*lp)++; | ||
215 | } | ||
216 | |||
217 | void | ||
218 | servconf_add_hostkey(const char *file, const int line, | ||
219 | ServerOptions *options, const char *path) | ||
220 | { | ||
221 | char *apath = derelativise_path(path); | ||
222 | |||
223 | array_append(file, line, "HostKey", | ||
224 | &options->host_key_files, &options->num_host_key_files, apath); | ||
225 | free(apath); | ||
226 | } | ||
227 | |||
228 | void | ||
229 | servconf_add_hostcert(const char *file, const int line, | ||
230 | ServerOptions *options, const char *path) | ||
231 | { | ||
232 | char *apath = derelativise_path(path); | ||
233 | |||
234 | array_append(file, line, "HostCertificate", | ||
235 | &options->host_cert_files, &options->num_host_cert_files, apath); | ||
236 | free(apath); | ||
237 | } | ||
238 | |||
194 | void | 239 | void |
195 | fill_default_server_options(ServerOptions *options) | 240 | fill_default_server_options(ServerOptions *options) |
196 | { | 241 | { |
197 | int i; | 242 | u_int i; |
198 | 243 | ||
199 | /* Portable-specific options */ | 244 | /* Portable-specific options */ |
200 | if (options->use_pam == -1) | 245 | if (options->use_pam == -1) |
@@ -203,14 +248,18 @@ fill_default_server_options(ServerOptions *options) | |||
203 | /* Standard Options */ | 248 | /* Standard Options */ |
204 | if (options->num_host_key_files == 0) { | 249 | if (options->num_host_key_files == 0) { |
205 | /* fill default hostkeys for protocols */ | 250 | /* fill default hostkeys for protocols */ |
206 | options->host_key_files[options->num_host_key_files++] = | 251 | servconf_add_hostkey("[default]", 0, options, |
207 | _PATH_HOST_RSA_KEY_FILE; | 252 | _PATH_HOST_RSA_KEY_FILE); |
208 | #ifdef OPENSSL_HAS_ECC | 253 | #ifdef OPENSSL_HAS_ECC |
209 | options->host_key_files[options->num_host_key_files++] = | 254 | servconf_add_hostkey("[default]", 0, options, |
210 | _PATH_HOST_ECDSA_KEY_FILE; | 255 | _PATH_HOST_ECDSA_KEY_FILE); |
211 | #endif | 256 | #endif |
212 | options->host_key_files[options->num_host_key_files++] = | 257 | servconf_add_hostkey("[default]", 0, options, |
213 | _PATH_HOST_ED25519_KEY_FILE; | 258 | _PATH_HOST_ED25519_KEY_FILE); |
259 | #ifdef WITH_XMSS | ||
260 | servconf_add_hostkey("[default]", 0, options, | ||
261 | _PATH_HOST_XMSS_KEY_FILE); | ||
262 | #endif /* WITH_XMSS */ | ||
214 | } | 263 | } |
215 | /* No certificates by default */ | 264 | /* No certificates by default */ |
216 | if (options->num_ports == 0) | 265 | if (options->num_ports == 0) |
@@ -218,7 +267,7 @@ fill_default_server_options(ServerOptions *options) | |||
218 | if (options->address_family == -1) | 267 | if (options->address_family == -1) |
219 | options->address_family = AF_UNSPEC; | 268 | options->address_family = AF_UNSPEC; |
220 | if (options->listen_addrs == NULL) | 269 | if (options->listen_addrs == NULL) |
221 | add_listen_addr(options, NULL, 0); | 270 | add_listen_addr(options, NULL, NULL, 0); |
222 | if (options->pid_file == NULL) | 271 | if (options->pid_file == NULL) |
223 | options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE); | 272 | options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE); |
224 | if (options->login_grace_time == -1) | 273 | if (options->login_grace_time == -1) |
@@ -318,10 +367,14 @@ fill_default_server_options(ServerOptions *options) | |||
318 | if (options->client_alive_count_max == -1) | 367 | if (options->client_alive_count_max == -1) |
319 | options->client_alive_count_max = 3; | 368 | options->client_alive_count_max = 3; |
320 | if (options->num_authkeys_files == 0) { | 369 | if (options->num_authkeys_files == 0) { |
321 | options->authorized_keys_files[options->num_authkeys_files++] = | 370 | array_append("[default]", 0, "AuthorizedKeysFiles", |
322 | xstrdup(_PATH_SSH_USER_PERMITTED_KEYS); | 371 | &options->authorized_keys_files, |
323 | options->authorized_keys_files[options->num_authkeys_files++] = | 372 | &options->num_authkeys_files, |
324 | xstrdup(_PATH_SSH_USER_PERMITTED_KEYS2); | 373 | _PATH_SSH_USER_PERMITTED_KEYS); |
374 | array_append("[default]", 0, "AuthorizedKeysFiles", | ||
375 | &options->authorized_keys_files, | ||
376 | &options->num_authkeys_files, | ||
377 | _PATH_SSH_USER_PERMITTED_KEYS2); | ||
325 | } | 378 | } |
326 | if (options->permit_tun == -1) | 379 | if (options->permit_tun == -1) |
327 | options->permit_tun = SSH_TUNMODE_NO; | 380 | options->permit_tun = SSH_TUNMODE_NO; |
@@ -365,6 +418,7 @@ fill_default_server_options(ServerOptions *options) | |||
365 | CLEAR_ON_NONE(options->authorized_principals_file); | 418 | CLEAR_ON_NONE(options->authorized_principals_file); |
366 | CLEAR_ON_NONE(options->adm_forced_command); | 419 | CLEAR_ON_NONE(options->adm_forced_command); |
367 | CLEAR_ON_NONE(options->chroot_directory); | 420 | CLEAR_ON_NONE(options->chroot_directory); |
421 | CLEAR_ON_NONE(options->routing_domain); | ||
368 | for (i = 0; i < options->num_host_key_files; i++) | 422 | for (i = 0; i < options->num_host_key_files; i++) |
369 | CLEAR_ON_NONE(options->host_key_files[i]); | 423 | CLEAR_ON_NONE(options->host_key_files[i]); |
370 | for (i = 0; i < options->num_host_cert_files; i++) | 424 | for (i = 0; i < options->num_host_cert_files; i++) |
@@ -400,8 +454,7 @@ typedef enum { | |||
400 | sPermitRootLogin, sLogFacility, sLogLevel, | 454 | sPermitRootLogin, sLogFacility, sLogLevel, |
401 | sRhostsRSAAuthentication, sRSAAuthentication, | 455 | sRhostsRSAAuthentication, sRSAAuthentication, |
402 | sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, | 456 | sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, |
403 | sKerberosGetAFSToken, | 457 | sKerberosGetAFSToken, sChallengeResponseAuthentication, |
404 | sKerberosTgtPassing, sChallengeResponseAuthentication, | ||
405 | sPasswordAuthentication, sKbdInteractiveAuthentication, | 458 | sPasswordAuthentication, sKbdInteractiveAuthentication, |
406 | sListenAddress, sAddressFamily, | 459 | sListenAddress, sAddressFamily, |
407 | sPrintMotd, sPrintLastLog, sIgnoreRhosts, | 460 | sPrintMotd, sPrintLastLog, sIgnoreRhosts, |
@@ -429,7 +482,7 @@ typedef enum { | |||
429 | sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, | 482 | sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, |
430 | sStreamLocalBindMask, sStreamLocalBindUnlink, | 483 | sStreamLocalBindMask, sStreamLocalBindUnlink, |
431 | sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, | 484 | sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, |
432 | sExposeAuthInfo, | 485 | sExposeAuthInfo, sRDomain, |
433 | sDebianBanner, | 486 | sDebianBanner, |
434 | sDeprecated, sIgnore, sUnsupported | 487 | sDeprecated, sIgnore, sUnsupported |
435 | } ServerOpCodes; | 488 | } ServerOpCodes; |
@@ -584,6 +637,7 @@ static struct { | |||
584 | { "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL }, | 637 | { "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL }, |
585 | { "disableforwarding", sDisableForwarding, SSHCFG_ALL }, | 638 | { "disableforwarding", sDisableForwarding, SSHCFG_ALL }, |
586 | { "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL }, | 639 | { "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL }, |
640 | { "rdomain", sRDomain, SSHCFG_ALL }, | ||
587 | { "debianbanner", sDebianBanner, SSHCFG_GLOBAL }, | 641 | { "debianbanner", sDebianBanner, SSHCFG_GLOBAL }, |
588 | { NULL, sBadOption, 0 } | 642 | { NULL, sBadOption, 0 } |
589 | }; | 643 | }; |
@@ -638,23 +692,51 @@ derelativise_path(const char *path) | |||
638 | } | 692 | } |
639 | 693 | ||
640 | static void | 694 | static void |
641 | add_listen_addr(ServerOptions *options, char *addr, int port) | 695 | add_listen_addr(ServerOptions *options, const char *addr, |
696 | const char *rdomain, int port) | ||
642 | { | 697 | { |
643 | u_int i; | 698 | u_int i; |
644 | 699 | ||
645 | if (port == 0) | 700 | if (port > 0) |
646 | for (i = 0; i < options->num_ports; i++) | 701 | add_one_listen_addr(options, addr, rdomain, port); |
647 | add_one_listen_addr(options, addr, options->ports[i]); | 702 | else { |
648 | else | 703 | for (i = 0; i < options->num_ports; i++) { |
649 | add_one_listen_addr(options, addr, port); | 704 | add_one_listen_addr(options, addr, rdomain, |
705 | options->ports[i]); | ||
706 | } | ||
707 | } | ||
650 | } | 708 | } |
651 | 709 | ||
652 | static void | 710 | static void |
653 | add_one_listen_addr(ServerOptions *options, char *addr, int port) | 711 | add_one_listen_addr(ServerOptions *options, const char *addr, |
712 | const char *rdomain, int port) | ||
654 | { | 713 | { |
655 | struct addrinfo hints, *ai, *aitop; | 714 | struct addrinfo hints, *ai, *aitop; |
656 | char strport[NI_MAXSERV]; | 715 | char strport[NI_MAXSERV]; |
657 | int gaierr; | 716 | int gaierr; |
717 | u_int i; | ||
718 | |||
719 | /* Find listen_addrs entry for this rdomain */ | ||
720 | for (i = 0; i < options->num_listen_addrs; i++) { | ||
721 | if (rdomain == NULL && options->listen_addrs[i].rdomain == NULL) | ||
722 | break; | ||
723 | if (rdomain == NULL || options->listen_addrs[i].rdomain == NULL) | ||
724 | continue; | ||
725 | if (strcmp(rdomain, options->listen_addrs[i].rdomain) == 0) | ||
726 | break; | ||
727 | } | ||
728 | if (i >= options->num_listen_addrs) { | ||
729 | /* No entry for this rdomain; allocate one */ | ||
730 | if (i >= INT_MAX) | ||
731 | fatal("%s: too many listen addresses", __func__); | ||
732 | options->listen_addrs = xrecallocarray(options->listen_addrs, | ||
733 | options->num_listen_addrs, options->num_listen_addrs + 1, | ||
734 | sizeof(*options->listen_addrs)); | ||
735 | i = options->num_listen_addrs++; | ||
736 | if (rdomain != NULL) | ||
737 | options->listen_addrs[i].rdomain = xstrdup(rdomain); | ||
738 | } | ||
739 | /* options->listen_addrs[i] points to the addresses for this rdomain */ | ||
658 | 740 | ||
659 | memset(&hints, 0, sizeof(hints)); | 741 | memset(&hints, 0, sizeof(hints)); |
660 | hints.ai_family = options->address_family; | 742 | hints.ai_family = options->address_family; |
@@ -667,8 +749,44 @@ add_one_listen_addr(ServerOptions *options, char *addr, int port) | |||
667 | ssh_gai_strerror(gaierr)); | 749 | ssh_gai_strerror(gaierr)); |
668 | for (ai = aitop; ai->ai_next; ai = ai->ai_next) | 750 | for (ai = aitop; ai->ai_next; ai = ai->ai_next) |
669 | ; | 751 | ; |
670 | ai->ai_next = options->listen_addrs; | 752 | ai->ai_next = options->listen_addrs[i].addrs; |
671 | options->listen_addrs = aitop; | 753 | options->listen_addrs[i].addrs = aitop; |
754 | } | ||
755 | |||
756 | /* Returns nonzero if the routing domain name is valid */ | ||
757 | static int | ||
758 | valid_rdomain(const char *name) | ||
759 | { | ||
760 | #if defined(HAVE_SYS_VALID_RDOMAIN) | ||
761 | return sys_valid_rdomain(name); | ||
762 | #elif defined(__OpenBSD__) | ||
763 | const char *errstr; | ||
764 | long long num; | ||
765 | struct rt_tableinfo info; | ||
766 | int mib[6]; | ||
767 | size_t miblen = sizeof(mib); | ||
768 | |||
769 | if (name == NULL) | ||
770 | return 1; | ||
771 | |||
772 | num = strtonum(name, 0, 255, &errstr); | ||
773 | if (errstr != NULL) | ||
774 | return 0; | ||
775 | |||
776 | /* Check whether the table actually exists */ | ||
777 | memset(mib, 0, sizeof(mib)); | ||
778 | mib[0] = CTL_NET; | ||
779 | mib[1] = PF_ROUTE; | ||
780 | mib[4] = NET_RT_TABLE; | ||
781 | mib[5] = (int)num; | ||
782 | if (sysctl(mib, 6, &info, &miblen, NULL, 0) == -1) | ||
783 | return 0; | ||
784 | |||
785 | return 1; | ||
786 | #else /* defined(__OpenBSD__) */ | ||
787 | error("Routing domains are not supported on this platform"); | ||
788 | return 0; | ||
789 | #endif | ||
672 | } | 790 | } |
673 | 791 | ||
674 | /* | 792 | /* |
@@ -676,18 +794,19 @@ add_one_listen_addr(ServerOptions *options, char *addr, int port) | |||
676 | * and AddressFamily options. | 794 | * and AddressFamily options. |
677 | */ | 795 | */ |
678 | static void | 796 | static void |
679 | queue_listen_addr(ServerOptions *options, char *addr, int port) | 797 | queue_listen_addr(ServerOptions *options, const char *addr, |
798 | const char *rdomain, int port) | ||
680 | { | 799 | { |
681 | options->queued_listen_addrs = xreallocarray( | 800 | struct queued_listenaddr *qla; |
682 | options->queued_listen_addrs, options->num_queued_listens + 1, | 801 | |
683 | sizeof(addr)); | 802 | options->queued_listen_addrs = xrecallocarray( |
684 | options->queued_listen_ports = xreallocarray( | 803 | options->queued_listen_addrs, |
685 | options->queued_listen_ports, options->num_queued_listens + 1, | 804 | options->num_queued_listens, options->num_queued_listens + 1, |
686 | sizeof(port)); | 805 | sizeof(*options->queued_listen_addrs)); |
687 | options->queued_listen_addrs[options->num_queued_listens] = | 806 | qla = &options->queued_listen_addrs[options->num_queued_listens++]; |
688 | xstrdup(addr); | 807 | qla->addr = xstrdup(addr); |
689 | options->queued_listen_ports[options->num_queued_listens] = port; | 808 | qla->port = port; |
690 | options->num_queued_listens++; | 809 | qla->rdomain = rdomain == NULL ? NULL : xstrdup(rdomain); |
691 | } | 810 | } |
692 | 811 | ||
693 | /* | 812 | /* |
@@ -697,6 +816,7 @@ static void | |||
697 | process_queued_listen_addrs(ServerOptions *options) | 816 | process_queued_listen_addrs(ServerOptions *options) |
698 | { | 817 | { |
699 | u_int i; | 818 | u_int i; |
819 | struct queued_listenaddr *qla; | ||
700 | 820 | ||
701 | if (options->num_ports == 0) | 821 | if (options->num_ports == 0) |
702 | options->ports[options->num_ports++] = SSH_DEFAULT_PORT; | 822 | options->ports[options->num_ports++] = SSH_DEFAULT_PORT; |
@@ -704,15 +824,13 @@ process_queued_listen_addrs(ServerOptions *options) | |||
704 | options->address_family = AF_UNSPEC; | 824 | options->address_family = AF_UNSPEC; |
705 | 825 | ||
706 | for (i = 0; i < options->num_queued_listens; i++) { | 826 | for (i = 0; i < options->num_queued_listens; i++) { |
707 | add_listen_addr(options, options->queued_listen_addrs[i], | 827 | qla = &options->queued_listen_addrs[i]; |
708 | options->queued_listen_ports[i]); | 828 | add_listen_addr(options, qla->addr, qla->rdomain, qla->port); |
709 | free(options->queued_listen_addrs[i]); | 829 | free(qla->addr); |
710 | options->queued_listen_addrs[i] = NULL; | 830 | free(qla->rdomain); |
711 | } | 831 | } |
712 | free(options->queued_listen_addrs); | 832 | free(options->queued_listen_addrs); |
713 | options->queued_listen_addrs = NULL; | 833 | options->queued_listen_addrs = NULL; |
714 | free(options->queued_listen_ports); | ||
715 | options->queued_listen_ports = NULL; | ||
716 | options->num_queued_listens = 0; | 834 | options->num_queued_listens = 0; |
717 | } | 835 | } |
718 | 836 | ||
@@ -766,6 +884,7 @@ get_connection_info(int populate, int use_dns) | |||
766 | ci.address = ssh_remote_ipaddr(ssh); | 884 | ci.address = ssh_remote_ipaddr(ssh); |
767 | ci.laddress = ssh_local_ipaddr(ssh); | 885 | ci.laddress = ssh_local_ipaddr(ssh); |
768 | ci.lport = ssh_local_port(ssh); | 886 | ci.lport = ssh_local_port(ssh); |
887 | ci.rdomain = ssh_packet_rdomain_in(ssh); | ||
769 | return &ci; | 888 | return &ci; |
770 | } | 889 | } |
771 | 890 | ||
@@ -830,6 +949,13 @@ out: | |||
830 | return result; | 949 | return result; |
831 | } | 950 | } |
832 | 951 | ||
952 | static void | ||
953 | match_test_missing_fatal(const char *criteria, const char *attrib) | ||
954 | { | ||
955 | fatal("'Match %s' in configuration but '%s' not in connection " | ||
956 | "test specification.", criteria, attrib); | ||
957 | } | ||
958 | |||
833 | /* | 959 | /* |
834 | * All of the attributes on a single Match line are ANDed together, so we need | 960 | * All of the attributes on a single Match line are ANDed together, so we need |
835 | * to check every attribute and set the result to zero if any attribute does | 961 | * to check every attribute and set the result to zero if any attribute does |
@@ -867,20 +993,24 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) | |||
867 | return -1; | 993 | return -1; |
868 | } | 994 | } |
869 | if (strcasecmp(attrib, "user") == 0) { | 995 | if (strcasecmp(attrib, "user") == 0) { |
870 | if (ci == NULL || ci->user == NULL) { | 996 | if (ci == NULL) { |
871 | result = 0; | 997 | result = 0; |
872 | continue; | 998 | continue; |
873 | } | 999 | } |
1000 | if (ci->user == NULL) | ||
1001 | match_test_missing_fatal("User", "user"); | ||
874 | if (match_pattern_list(ci->user, arg, 0) != 1) | 1002 | if (match_pattern_list(ci->user, arg, 0) != 1) |
875 | result = 0; | 1003 | result = 0; |
876 | else | 1004 | else |
877 | debug("user %.100s matched 'User %.100s' at " | 1005 | debug("user %.100s matched 'User %.100s' at " |
878 | "line %d", ci->user, arg, line); | 1006 | "line %d", ci->user, arg, line); |
879 | } else if (strcasecmp(attrib, "group") == 0) { | 1007 | } else if (strcasecmp(attrib, "group") == 0) { |
880 | if (ci == NULL || ci->user == NULL) { | 1008 | if (ci == NULL) { |
881 | result = 0; | 1009 | result = 0; |
882 | continue; | 1010 | continue; |
883 | } | 1011 | } |
1012 | if (ci->user == NULL) | ||
1013 | match_test_missing_fatal("Group", "user"); | ||
884 | switch (match_cfg_line_group(arg, line, ci->user)) { | 1014 | switch (match_cfg_line_group(arg, line, ci->user)) { |
885 | case -1: | 1015 | case -1: |
886 | return -1; | 1016 | return -1; |
@@ -888,20 +1018,24 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) | |||
888 | result = 0; | 1018 | result = 0; |
889 | } | 1019 | } |
890 | } else if (strcasecmp(attrib, "host") == 0) { | 1020 | } else if (strcasecmp(attrib, "host") == 0) { |
891 | if (ci == NULL || ci->host == NULL) { | 1021 | if (ci == NULL) { |
892 | result = 0; | 1022 | result = 0; |
893 | continue; | 1023 | continue; |
894 | } | 1024 | } |
1025 | if (ci->host == NULL) | ||
1026 | match_test_missing_fatal("Host", "host"); | ||
895 | if (match_hostname(ci->host, arg) != 1) | 1027 | if (match_hostname(ci->host, arg) != 1) |
896 | result = 0; | 1028 | result = 0; |
897 | else | 1029 | else |
898 | debug("connection from %.100s matched 'Host " | 1030 | debug("connection from %.100s matched 'Host " |
899 | "%.100s' at line %d", ci->host, arg, line); | 1031 | "%.100s' at line %d", ci->host, arg, line); |
900 | } else if (strcasecmp(attrib, "address") == 0) { | 1032 | } else if (strcasecmp(attrib, "address") == 0) { |
901 | if (ci == NULL || ci->address == NULL) { | 1033 | if (ci == NULL) { |
902 | result = 0; | 1034 | result = 0; |
903 | continue; | 1035 | continue; |
904 | } | 1036 | } |
1037 | if (ci->address == NULL) | ||
1038 | match_test_missing_fatal("Address", "addr"); | ||
905 | switch (addr_match_list(ci->address, arg)) { | 1039 | switch (addr_match_list(ci->address, arg)) { |
906 | case 1: | 1040 | case 1: |
907 | debug("connection from %.100s matched 'Address " | 1041 | debug("connection from %.100s matched 'Address " |
@@ -915,10 +1049,13 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) | |||
915 | return -1; | 1049 | return -1; |
916 | } | 1050 | } |
917 | } else if (strcasecmp(attrib, "localaddress") == 0){ | 1051 | } else if (strcasecmp(attrib, "localaddress") == 0){ |
918 | if (ci == NULL || ci->laddress == NULL) { | 1052 | if (ci == NULL) { |
919 | result = 0; | 1053 | result = 0; |
920 | continue; | 1054 | continue; |
921 | } | 1055 | } |
1056 | if (ci->laddress == NULL) | ||
1057 | match_test_missing_fatal("LocalAddress", | ||
1058 | "laddr"); | ||
922 | switch (addr_match_list(ci->laddress, arg)) { | 1059 | switch (addr_match_list(ci->laddress, arg)) { |
923 | case 1: | 1060 | case 1: |
924 | debug("connection from %.100s matched " | 1061 | debug("connection from %.100s matched " |
@@ -938,10 +1075,12 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) | |||
938 | arg); | 1075 | arg); |
939 | return -1; | 1076 | return -1; |
940 | } | 1077 | } |
941 | if (ci == NULL || ci->lport == 0) { | 1078 | if (ci == NULL) { |
942 | result = 0; | 1079 | result = 0; |
943 | continue; | 1080 | continue; |
944 | } | 1081 | } |
1082 | if (ci->lport == 0) | ||
1083 | match_test_missing_fatal("LocalPort", "lport"); | ||
945 | /* TODO support port lists */ | 1084 | /* TODO support port lists */ |
946 | if (port == ci->lport) | 1085 | if (port == ci->lport) |
947 | debug("connection from %.100s matched " | 1086 | debug("connection from %.100s matched " |
@@ -949,6 +1088,16 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) | |||
949 | ci->laddress, port, line); | 1088 | ci->laddress, port, line); |
950 | else | 1089 | else |
951 | result = 0; | 1090 | result = 0; |
1091 | } else if (strcasecmp(attrib, "rdomain") == 0) { | ||
1092 | if (ci == NULL || ci->rdomain == NULL) { | ||
1093 | result = 0; | ||
1094 | continue; | ||
1095 | } | ||
1096 | if (match_pattern_list(ci->rdomain, arg, 0) != 1) | ||
1097 | result = 0; | ||
1098 | else | ||
1099 | debug("user %.100s matched 'RDomain %.100s' at " | ||
1100 | "line %d", ci->rdomain, arg, line); | ||
952 | } else { | 1101 | } else { |
953 | error("Unsupported Match attribute %s", attrib); | 1102 | error("Unsupported Match attribute %s", attrib); |
954 | return -1; | 1103 | return -1; |
@@ -971,6 +1120,11 @@ struct multistate { | |||
971 | char *key; | 1120 | char *key; |
972 | int value; | 1121 | int value; |
973 | }; | 1122 | }; |
1123 | static const struct multistate multistate_flag[] = { | ||
1124 | { "yes", 1 }, | ||
1125 | { "no", 0 }, | ||
1126 | { NULL, -1 } | ||
1127 | }; | ||
974 | static const struct multistate multistate_addressfamily[] = { | 1128 | static const struct multistate multistate_addressfamily[] = { |
975 | { "inet", AF_INET }, | 1129 | { "inet", AF_INET }, |
976 | { "inet6", AF_INET6 }, | 1130 | { "inet6", AF_INET6 }, |
@@ -1020,6 +1174,7 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1020 | size_t len; | 1174 | size_t len; |
1021 | long long val64; | 1175 | long long val64; |
1022 | const struct multistate *multistate_ptr; | 1176 | const struct multistate *multistate_ptr; |
1177 | const char *errstr; | ||
1023 | 1178 | ||
1024 | /* Strip trailing whitespace. Allow \f (form feed) at EOL only */ | 1179 | /* Strip trailing whitespace. Allow \f (form feed) at EOL only */ |
1025 | if ((len = strlen(line)) == 0) | 1180 | if ((len = strlen(line)) == 0) |
@@ -1107,20 +1262,33 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1107 | /* check for bare IPv6 address: no "[]" and 2 or more ":" */ | 1262 | /* check for bare IPv6 address: no "[]" and 2 or more ":" */ |
1108 | if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL | 1263 | if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL |
1109 | && strchr(p+1, ':') != NULL) { | 1264 | && strchr(p+1, ':') != NULL) { |
1110 | queue_listen_addr(options, arg, 0); | ||
1111 | break; | ||
1112 | } | ||
1113 | p = hpdelim(&arg); | ||
1114 | if (p == NULL) | ||
1115 | fatal("%s line %d: bad address:port usage", | ||
1116 | filename, linenum); | ||
1117 | p = cleanhostname(p); | ||
1118 | if (arg == NULL) | ||
1119 | port = 0; | 1265 | port = 0; |
1120 | else if ((port = a2port(arg)) <= 0) | 1266 | p = arg; |
1121 | fatal("%s line %d: bad port number", filename, linenum); | 1267 | } else { |
1268 | p = hpdelim(&arg); | ||
1269 | if (p == NULL) | ||
1270 | fatal("%s line %d: bad address:port usage", | ||
1271 | filename, linenum); | ||
1272 | p = cleanhostname(p); | ||
1273 | if (arg == NULL) | ||
1274 | port = 0; | ||
1275 | else if ((port = a2port(arg)) <= 0) | ||
1276 | fatal("%s line %d: bad port number", | ||
1277 | filename, linenum); | ||
1278 | } | ||
1279 | /* Optional routing table */ | ||
1280 | arg2 = NULL; | ||
1281 | if ((arg = strdelim(&cp)) != NULL) { | ||
1282 | if (strcmp(arg, "rdomain") != 0 || | ||
1283 | (arg2 = strdelim(&cp)) == NULL) | ||
1284 | fatal("%s line %d: bad ListenAddress syntax", | ||
1285 | filename, linenum); | ||
1286 | if (!valid_rdomain(arg2)) | ||
1287 | fatal("%s line %d: bad routing domain", | ||
1288 | filename, linenum); | ||
1289 | } | ||
1122 | 1290 | ||
1123 | queue_listen_addr(options, p, port); | 1291 | queue_listen_addr(options, p, arg2, port); |
1124 | 1292 | ||
1125 | break; | 1293 | break; |
1126 | 1294 | ||
@@ -1147,22 +1315,12 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1147 | break; | 1315 | break; |
1148 | 1316 | ||
1149 | case sHostKeyFile: | 1317 | case sHostKeyFile: |
1150 | intptr = &options->num_host_key_files; | ||
1151 | if (*intptr >= MAX_HOSTKEYS) | ||
1152 | fatal("%s line %d: too many host keys specified (max %d).", | ||
1153 | filename, linenum, MAX_HOSTKEYS); | ||
1154 | charptr = &options->host_key_files[*intptr]; | ||
1155 | parse_filename: | ||
1156 | arg = strdelim(&cp); | 1318 | arg = strdelim(&cp); |
1157 | if (!arg || *arg == '\0') | 1319 | if (!arg || *arg == '\0') |
1158 | fatal("%s line %d: missing file name.", | 1320 | fatal("%s line %d: missing file name.", |
1159 | filename, linenum); | 1321 | filename, linenum); |
1160 | if (*activep && *charptr == NULL) { | 1322 | if (*activep) |
1161 | *charptr = derelativise_path(arg); | 1323 | servconf_add_hostkey(filename, linenum, options, arg); |
1162 | /* increase optional counter */ | ||
1163 | if (intptr != NULL) | ||
1164 | *intptr = *intptr + 1; | ||
1165 | } | ||
1166 | break; | 1324 | break; |
1167 | 1325 | ||
1168 | case sHostKeyAgent: | 1326 | case sHostKeyAgent: |
@@ -1177,17 +1335,28 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1177 | break; | 1335 | break; |
1178 | 1336 | ||
1179 | case sHostCertificate: | 1337 | case sHostCertificate: |
1180 | intptr = &options->num_host_cert_files; | 1338 | arg = strdelim(&cp); |
1181 | if (*intptr >= MAX_HOSTKEYS) | 1339 | if (!arg || *arg == '\0') |
1182 | fatal("%s line %d: too many host certificates " | 1340 | fatal("%s line %d: missing file name.", |
1183 | "specified (max %d).", filename, linenum, | 1341 | filename, linenum); |
1184 | MAX_HOSTCERTS); | 1342 | if (*activep) |
1185 | charptr = &options->host_cert_files[*intptr]; | 1343 | servconf_add_hostcert(filename, linenum, options, arg); |
1186 | goto parse_filename; | 1344 | break; |
1187 | 1345 | ||
1188 | case sPidFile: | 1346 | case sPidFile: |
1189 | charptr = &options->pid_file; | 1347 | charptr = &options->pid_file; |
1190 | goto parse_filename; | 1348 | parse_filename: |
1349 | arg = strdelim(&cp); | ||
1350 | if (!arg || *arg == '\0') | ||
1351 | fatal("%s line %d: missing file name.", | ||
1352 | filename, linenum); | ||
1353 | if (*activep && *charptr == NULL) { | ||
1354 | *charptr = derelativise_path(arg); | ||
1355 | /* increase optional counter */ | ||
1356 | if (intptr != NULL) | ||
1357 | *intptr = *intptr + 1; | ||
1358 | } | ||
1359 | break; | ||
1191 | 1360 | ||
1192 | case sPermitRootLogin: | 1361 | case sPermitRootLogin: |
1193 | intptr = &options->permit_root_login; | 1362 | intptr = &options->permit_root_login; |
@@ -1197,21 +1366,8 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1197 | case sIgnoreRhosts: | 1366 | case sIgnoreRhosts: |
1198 | intptr = &options->ignore_rhosts; | 1367 | intptr = &options->ignore_rhosts; |
1199 | parse_flag: | 1368 | parse_flag: |
1200 | arg = strdelim(&cp); | 1369 | multistate_ptr = multistate_flag; |
1201 | if (!arg || *arg == '\0') | 1370 | goto parse_multistate; |
1202 | fatal("%s line %d: missing yes/no argument.", | ||
1203 | filename, linenum); | ||
1204 | value = 0; /* silence compiler */ | ||
1205 | if (strcmp(arg, "yes") == 0) | ||
1206 | value = 1; | ||
1207 | else if (strcmp(arg, "no") == 0) | ||
1208 | value = 0; | ||
1209 | else | ||
1210 | fatal("%s line %d: Bad yes/no argument: %s", | ||
1211 | filename, linenum, arg); | ||
1212 | if (*activep && *intptr == -1) | ||
1213 | *intptr = value; | ||
1214 | break; | ||
1215 | 1371 | ||
1216 | case sIgnoreUserKnownHosts: | 1372 | case sIgnoreUserKnownHosts: |
1217 | intptr = &options->ignore_user_known_hosts; | 1373 | intptr = &options->ignore_user_known_hosts; |
@@ -1316,10 +1472,9 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1316 | intptr = &options->x11_display_offset; | 1472 | intptr = &options->x11_display_offset; |
1317 | parse_int: | 1473 | parse_int: |
1318 | arg = strdelim(&cp); | 1474 | arg = strdelim(&cp); |
1319 | if (!arg || *arg == '\0') | 1475 | if ((errstr = atoi_err(arg, &value)) != NULL) |
1320 | fatal("%s line %d: missing integer value.", | 1476 | fatal("%s line %d: integer value %s.", |
1321 | filename, linenum); | 1477 | filename, linenum, errstr); |
1322 | value = atoi(arg); | ||
1323 | if (*activep && *intptr == -1) | 1478 | if (*activep && *intptr == -1) |
1324 | *intptr = value; | 1479 | *intptr = value; |
1325 | break; | 1480 | break; |
@@ -1439,55 +1594,47 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1439 | 1594 | ||
1440 | case sAllowUsers: | 1595 | case sAllowUsers: |
1441 | while ((arg = strdelim(&cp)) && *arg != '\0') { | 1596 | while ((arg = strdelim(&cp)) && *arg != '\0') { |
1442 | if (options->num_allow_users >= MAX_ALLOW_USERS) | ||
1443 | fatal("%s line %d: too many allow users.", | ||
1444 | filename, linenum); | ||
1445 | if (match_user(NULL, NULL, NULL, arg) == -1) | 1597 | if (match_user(NULL, NULL, NULL, arg) == -1) |
1446 | fatal("%s line %d: invalid AllowUsers pattern: " | 1598 | fatal("%s line %d: invalid AllowUsers pattern: " |
1447 | "\"%.100s\"", filename, linenum, arg); | 1599 | "\"%.100s\"", filename, linenum, arg); |
1448 | if (!*activep) | 1600 | if (!*activep) |
1449 | continue; | 1601 | continue; |
1450 | options->allow_users[options->num_allow_users++] = | 1602 | array_append(filename, linenum, "AllowUsers", |
1451 | xstrdup(arg); | 1603 | &options->allow_users, &options->num_allow_users, |
1604 | arg); | ||
1452 | } | 1605 | } |
1453 | break; | 1606 | break; |
1454 | 1607 | ||
1455 | case sDenyUsers: | 1608 | case sDenyUsers: |
1456 | while ((arg = strdelim(&cp)) && *arg != '\0') { | 1609 | while ((arg = strdelim(&cp)) && *arg != '\0') { |
1457 | if (options->num_deny_users >= MAX_DENY_USERS) | ||
1458 | fatal("%s line %d: too many deny users.", | ||
1459 | filename, linenum); | ||
1460 | if (match_user(NULL, NULL, NULL, arg) == -1) | 1610 | if (match_user(NULL, NULL, NULL, arg) == -1) |
1461 | fatal("%s line %d: invalid DenyUsers pattern: " | 1611 | fatal("%s line %d: invalid DenyUsers pattern: " |
1462 | "\"%.100s\"", filename, linenum, arg); | 1612 | "\"%.100s\"", filename, linenum, arg); |
1463 | if (!*activep) | 1613 | if (!*activep) |
1464 | continue; | 1614 | continue; |
1465 | options->deny_users[options->num_deny_users++] = | 1615 | array_append(filename, linenum, "DenyUsers", |
1466 | xstrdup(arg); | 1616 | &options->deny_users, &options->num_deny_users, |
1617 | arg); | ||
1467 | } | 1618 | } |
1468 | break; | 1619 | break; |
1469 | 1620 | ||
1470 | case sAllowGroups: | 1621 | case sAllowGroups: |
1471 | while ((arg = strdelim(&cp)) && *arg != '\0') { | 1622 | while ((arg = strdelim(&cp)) && *arg != '\0') { |
1472 | if (options->num_allow_groups >= MAX_ALLOW_GROUPS) | ||
1473 | fatal("%s line %d: too many allow groups.", | ||
1474 | filename, linenum); | ||
1475 | if (!*activep) | 1623 | if (!*activep) |
1476 | continue; | 1624 | continue; |
1477 | options->allow_groups[options->num_allow_groups++] = | 1625 | array_append(filename, linenum, "AllowGroups", |
1478 | xstrdup(arg); | 1626 | &options->allow_groups, &options->num_allow_groups, |
1627 | arg); | ||
1479 | } | 1628 | } |
1480 | break; | 1629 | break; |
1481 | 1630 | ||
1482 | case sDenyGroups: | 1631 | case sDenyGroups: |
1483 | while ((arg = strdelim(&cp)) && *arg != '\0') { | 1632 | while ((arg = strdelim(&cp)) && *arg != '\0') { |
1484 | if (options->num_deny_groups >= MAX_DENY_GROUPS) | ||
1485 | fatal("%s line %d: too many deny groups.", | ||
1486 | filename, linenum); | ||
1487 | if (!*activep) | 1633 | if (!*activep) |
1488 | continue; | 1634 | continue; |
1489 | options->deny_groups[options->num_deny_groups++] = | 1635 | array_append(filename, linenum, "DenyGroups", |
1490 | xstrdup(arg); | 1636 | &options->deny_groups, &options->num_deny_groups, |
1637 | arg); | ||
1491 | } | 1638 | } |
1492 | break; | 1639 | break; |
1493 | 1640 | ||
@@ -1606,14 +1753,12 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1606 | case sAuthorizedKeysFile: | 1753 | case sAuthorizedKeysFile: |
1607 | if (*activep && options->num_authkeys_files == 0) { | 1754 | if (*activep && options->num_authkeys_files == 0) { |
1608 | while ((arg = strdelim(&cp)) && *arg != '\0') { | 1755 | while ((arg = strdelim(&cp)) && *arg != '\0') { |
1609 | if (options->num_authkeys_files >= | 1756 | arg = tilde_expand_filename(arg, getuid()); |
1610 | MAX_AUTHKEYS_FILES) | 1757 | array_append(filename, linenum, |
1611 | fatal("%s line %d: " | 1758 | "AuthorizedKeysFile", |
1612 | "too many authorized keys files.", | 1759 | &options->authorized_keys_files, |
1613 | filename, linenum); | 1760 | &options->num_authkeys_files, arg); |
1614 | options->authorized_keys_files[ | 1761 | free(arg); |
1615 | options->num_authkeys_files++] = | ||
1616 | tilde_expand_filename(arg, getuid()); | ||
1617 | } | 1762 | } |
1618 | } | 1763 | } |
1619 | return 0; | 1764 | return 0; |
@@ -1645,13 +1790,11 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1645 | if (strchr(arg, '=') != NULL) | 1790 | if (strchr(arg, '=') != NULL) |
1646 | fatal("%s line %d: Invalid environment name.", | 1791 | fatal("%s line %d: Invalid environment name.", |
1647 | filename, linenum); | 1792 | filename, linenum); |
1648 | if (options->num_accept_env >= MAX_ACCEPT_ENV) | ||
1649 | fatal("%s line %d: too many allow env.", | ||
1650 | filename, linenum); | ||
1651 | if (!*activep) | 1793 | if (!*activep) |
1652 | continue; | 1794 | continue; |
1653 | options->accept_env[options->num_accept_env++] = | 1795 | array_append(filename, linenum, "AcceptEnv", |
1654 | xstrdup(arg); | 1796 | &options->accept_env, &options->num_accept_env, |
1797 | arg); | ||
1655 | } | 1798 | } |
1656 | break; | 1799 | break; |
1657 | 1800 | ||
@@ -1711,15 +1854,12 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1711 | fatal("%s line %d: bad port number in " | 1854 | fatal("%s line %d: bad port number in " |
1712 | "PermitOpen", filename, linenum); | 1855 | "PermitOpen", filename, linenum); |
1713 | if (*activep && value == 0) { | 1856 | if (*activep && value == 0) { |
1714 | options->permitted_opens = xrecallocarray( | 1857 | array_append(filename, linenum, |
1715 | options->permitted_opens, | 1858 | "PermitOpen", |
1716 | options->num_permitted_opens, | 1859 | &options->permitted_opens, |
1717 | options->num_permitted_opens + 1, | 1860 | &options->num_permitted_opens, arg2); |
1718 | sizeof(*options->permitted_opens)); | 1861 | } |
1719 | i = options->num_permitted_opens++; | 1862 | free(arg2); |
1720 | options->permitted_opens[i] = arg2; | ||
1721 | } else | ||
1722 | free(arg2); | ||
1723 | } | 1863 | } |
1724 | break; | 1864 | break; |
1725 | 1865 | ||
@@ -1842,11 +1982,6 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1842 | value = 0; /* seen "any" pseudo-method */ | 1982 | value = 0; /* seen "any" pseudo-method */ |
1843 | value2 = 0; /* sucessfully parsed any method */ | 1983 | value2 = 0; /* sucessfully parsed any method */ |
1844 | while ((arg = strdelim(&cp)) && *arg != '\0') { | 1984 | while ((arg = strdelim(&cp)) && *arg != '\0') { |
1845 | if (options->num_auth_methods >= | ||
1846 | MAX_AUTH_METHODS) | ||
1847 | fatal("%s line %d: " | ||
1848 | "too many authentication methods.", | ||
1849 | filename, linenum); | ||
1850 | if (strcmp(arg, "any") == 0) { | 1985 | if (strcmp(arg, "any") == 0) { |
1851 | if (options->num_auth_methods > 0) { | 1986 | if (options->num_auth_methods > 0) { |
1852 | fatal("%s line %d: \"any\" " | 1987 | fatal("%s line %d: \"any\" " |
@@ -1867,8 +2002,10 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1867 | value2 = 1; | 2002 | value2 = 1; |
1868 | if (!*activep) | 2003 | if (!*activep) |
1869 | continue; | 2004 | continue; |
1870 | options->auth_methods[ | 2005 | array_append(filename, linenum, |
1871 | options->num_auth_methods++] = xstrdup(arg); | 2006 | "AuthenticationMethods", |
2007 | &options->auth_methods, | ||
2008 | &options->num_auth_methods, arg); | ||
1872 | } | 2009 | } |
1873 | if (value2 == 0) { | 2010 | if (value2 == 0) { |
1874 | fatal("%s line %d: no AuthenticationMethods " | 2011 | fatal("%s line %d: no AuthenticationMethods " |
@@ -1910,9 +2047,23 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1910 | intptr = &options->expose_userauth_info; | 2047 | intptr = &options->expose_userauth_info; |
1911 | goto parse_flag; | 2048 | goto parse_flag; |
1912 | 2049 | ||
2050 | case sRDomain: | ||
2051 | charptr = &options->routing_domain; | ||
2052 | arg = strdelim(&cp); | ||
2053 | if (!arg || *arg == '\0') | ||
2054 | fatal("%.200s line %d: Missing argument.", | ||
2055 | filename, linenum); | ||
2056 | if (strcasecmp(arg, "none") != 0 && strcmp(arg, "%D") != 0 && | ||
2057 | !valid_rdomain(arg)) | ||
2058 | fatal("%s line %d: bad routing domain", | ||
2059 | filename, linenum); | ||
2060 | if (*activep && *charptr == NULL) | ||
2061 | *charptr = xstrdup(arg); | ||
2062 | break; | ||
2063 | |||
1913 | case sDebianBanner: | 2064 | case sDebianBanner: |
1914 | intptr = &options->debian_banner; | 2065 | intptr = &options->debian_banner; |
1915 | goto parse_int; | 2066 | goto parse_flag; |
1916 | 2067 | ||
1917 | case sDeprecated: | 2068 | case sDeprecated: |
1918 | case sIgnore: | 2069 | case sIgnore: |
@@ -1994,6 +2145,8 @@ int parse_server_match_testspec(struct connection_info *ci, char *spec) | |||
1994 | ci->user = xstrdup(p + 5); | 2145 | ci->user = xstrdup(p + 5); |
1995 | } else if (strncmp(p, "laddr=", 6) == 0) { | 2146 | } else if (strncmp(p, "laddr=", 6) == 0) { |
1996 | ci->laddress = xstrdup(p + 6); | 2147 | ci->laddress = xstrdup(p + 6); |
2148 | } else if (strncmp(p, "rdomain=", 8) == 0) { | ||
2149 | ci->rdomain = xstrdup(p + 8); | ||
1997 | } else if (strncmp(p, "lport=", 6) == 0) { | 2150 | } else if (strncmp(p, "lport=", 6) == 0) { |
1998 | ci->lport = a2port(p + 6); | 2151 | ci->lport = a2port(p + 6); |
1999 | if (ci->lport == -1) { | 2152 | if (ci->lport == -1) { |
@@ -2011,19 +2164,6 @@ int parse_server_match_testspec(struct connection_info *ci, char *spec) | |||
2011 | } | 2164 | } |
2012 | 2165 | ||
2013 | /* | 2166 | /* |
2014 | * returns 1 for a complete spec, 0 for partial spec and -1 for an | ||
2015 | * empty spec. | ||
2016 | */ | ||
2017 | int server_match_spec_complete(struct connection_info *ci) | ||
2018 | { | ||
2019 | if (ci->user && ci->host && ci->address) | ||
2020 | return 1; /* complete */ | ||
2021 | if (!ci->user && !ci->host && !ci->address) | ||
2022 | return -1; /* empty */ | ||
2023 | return 0; /* partial */ | ||
2024 | } | ||
2025 | |||
2026 | /* | ||
2027 | * Copy any supported values that are set. | 2167 | * Copy any supported values that are set. |
2028 | * | 2168 | * |
2029 | * If the preauth flag is set, we do not bother copying the string or | 2169 | * If the preauth flag is set, we do not bother copying the string or |
@@ -2088,17 +2228,16 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) | |||
2088 | dst->n = src->n; \ | 2228 | dst->n = src->n; \ |
2089 | } \ | 2229 | } \ |
2090 | } while(0) | 2230 | } while(0) |
2091 | #define M_CP_STRARRAYOPT(n, num_n) do {\ | 2231 | #define M_CP_STRARRAYOPT(s, num_s) do {\ |
2092 | if (src->num_n != 0) { \ | 2232 | u_int i; \ |
2093 | for (dst->num_n = 0; dst->num_n < src->num_n; dst->num_n++) \ | 2233 | if (src->num_s != 0) { \ |
2094 | dst->n[dst->num_n] = xstrdup(src->n[dst->num_n]); \ | 2234 | for (i = 0; i < dst->num_s; i++) \ |
2095 | } \ | 2235 | free(dst->s[i]); \ |
2096 | } while(0) | 2236 | free(dst->s); \ |
2097 | #define M_CP_STRARRAYOPT_ALLOC(n, num_n) do { \ | 2237 | dst->s = xcalloc(src->num_s, sizeof(*dst->s)); \ |
2098 | if (src->num_n != 0) { \ | 2238 | for (i = 0; i < src->num_s; i++) \ |
2099 | dst->n = xcalloc(src->num_n, sizeof(*dst->n)); \ | 2239 | dst->s[i] = xstrdup(src->s[i]); \ |
2100 | M_CP_STRARRAYOPT(n, num_n); \ | 2240 | dst->num_s = src->num_s; \ |
2101 | dst->num_n = src->num_n; \ | ||
2102 | } \ | 2241 | } \ |
2103 | } while(0) | 2242 | } while(0) |
2104 | 2243 | ||
@@ -2131,7 +2270,6 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) | |||
2131 | #undef M_CP_INTOPT | 2270 | #undef M_CP_INTOPT |
2132 | #undef M_CP_STROPT | 2271 | #undef M_CP_STROPT |
2133 | #undef M_CP_STRARRAYOPT | 2272 | #undef M_CP_STRARRAYOPT |
2134 | #undef M_CP_STRARRAYOPT_ALLOC | ||
2135 | 2273 | ||
2136 | void | 2274 | void |
2137 | parse_server_config(ServerOptions *options, const char *filename, Buffer *conf, | 2275 | parse_server_config(ServerOptions *options, const char *filename, Buffer *conf, |
@@ -2262,45 +2400,61 @@ dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals) | |||
2262 | printf("\n"); | 2400 | printf("\n"); |
2263 | } | 2401 | } |
2264 | 2402 | ||
2265 | void | 2403 | static char * |
2266 | dump_config(ServerOptions *o) | 2404 | format_listen_addrs(struct listenaddr *la) |
2267 | { | 2405 | { |
2268 | u_int i; | 2406 | int r; |
2269 | int ret; | ||
2270 | struct addrinfo *ai; | 2407 | struct addrinfo *ai; |
2271 | char addr[NI_MAXHOST], port[NI_MAXSERV], *s = NULL; | 2408 | char addr[NI_MAXHOST], port[NI_MAXSERV]; |
2272 | char *laddr1 = xstrdup(""), *laddr2 = NULL; | 2409 | char *laddr1 = xstrdup(""), *laddr2 = NULL; |
2273 | 2410 | ||
2274 | /* these are usually at the top of the config */ | ||
2275 | for (i = 0; i < o->num_ports; i++) | ||
2276 | printf("port %d\n", o->ports[i]); | ||
2277 | dump_cfg_fmtint(sAddressFamily, o->address_family); | ||
2278 | |||
2279 | /* | 2411 | /* |
2280 | * ListenAddress must be after Port. add_one_listen_addr pushes | 2412 | * ListenAddress must be after Port. add_one_listen_addr pushes |
2281 | * addresses onto a stack, so to maintain ordering we need to | 2413 | * addresses onto a stack, so to maintain ordering we need to |
2282 | * print these in reverse order. | 2414 | * print these in reverse order. |
2283 | */ | 2415 | */ |
2284 | for (ai = o->listen_addrs; ai; ai = ai->ai_next) { | 2416 | for (ai = la->addrs; ai; ai = ai->ai_next) { |
2285 | if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr, | 2417 | if ((r = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr, |
2286 | sizeof(addr), port, sizeof(port), | 2418 | sizeof(addr), port, sizeof(port), |
2287 | NI_NUMERICHOST|NI_NUMERICSERV)) != 0) { | 2419 | NI_NUMERICHOST|NI_NUMERICSERV)) != 0) { |
2288 | error("getnameinfo failed: %.100s", | 2420 | error("getnameinfo: %.100s", ssh_gai_strerror(r)); |
2289 | (ret != EAI_SYSTEM) ? gai_strerror(ret) : | 2421 | continue; |
2290 | strerror(errno)); | 2422 | } |
2423 | laddr2 = laddr1; | ||
2424 | if (ai->ai_family == AF_INET6) { | ||
2425 | xasprintf(&laddr1, "listenaddress [%s]:%s%s%s\n%s", | ||
2426 | addr, port, | ||
2427 | la->rdomain == NULL ? "" : " rdomain ", | ||
2428 | la->rdomain == NULL ? "" : la->rdomain, | ||
2429 | laddr2); | ||
2291 | } else { | 2430 | } else { |
2292 | laddr2 = laddr1; | 2431 | xasprintf(&laddr1, "listenaddress %s:%s%s%s\n%s", |
2293 | if (ai->ai_family == AF_INET6) | 2432 | addr, port, |
2294 | xasprintf(&laddr1, "listenaddress [%s]:%s\n%s", | 2433 | la->rdomain == NULL ? "" : " rdomain ", |
2295 | addr, port, laddr2); | 2434 | la->rdomain == NULL ? "" : la->rdomain, |
2296 | else | 2435 | laddr2); |
2297 | xasprintf(&laddr1, "listenaddress %s:%s\n%s", | ||
2298 | addr, port, laddr2); | ||
2299 | free(laddr2); | ||
2300 | } | 2436 | } |
2437 | free(laddr2); | ||
2438 | } | ||
2439 | return laddr1; | ||
2440 | } | ||
2441 | |||
2442 | void | ||
2443 | dump_config(ServerOptions *o) | ||
2444 | { | ||
2445 | char *s; | ||
2446 | u_int i; | ||
2447 | |||
2448 | /* these are usually at the top of the config */ | ||
2449 | for (i = 0; i < o->num_ports; i++) | ||
2450 | printf("port %d\n", o->ports[i]); | ||
2451 | dump_cfg_fmtint(sAddressFamily, o->address_family); | ||
2452 | |||
2453 | for (i = 0; i < o->num_listen_addrs; i++) { | ||
2454 | s = format_listen_addrs(&o->listen_addrs[i]); | ||
2455 | printf("%s", s); | ||
2456 | free(s); | ||
2301 | } | 2457 | } |
2302 | printf("%s", laddr1); | ||
2303 | free(laddr1); | ||
2304 | 2458 | ||
2305 | /* integer arguments */ | 2459 | /* integer arguments */ |
2306 | #ifdef USE_PAM | 2460 | #ifdef USE_PAM |
@@ -2392,6 +2546,7 @@ dump_config(ServerOptions *o) | |||
2392 | o->hostkeyalgorithms : KEX_DEFAULT_PK_ALG); | 2546 | o->hostkeyalgorithms : KEX_DEFAULT_PK_ALG); |
2393 | dump_cfg_string(sPubkeyAcceptedKeyTypes, o->pubkey_key_types ? | 2547 | dump_cfg_string(sPubkeyAcceptedKeyTypes, o->pubkey_key_types ? |
2394 | o->pubkey_key_types : KEX_DEFAULT_PK_ALG); | 2548 | o->pubkey_key_types : KEX_DEFAULT_PK_ALG); |
2549 | dump_cfg_string(sRDomain, o->routing_domain); | ||
2395 | 2550 | ||
2396 | /* string arguments requiring a lookup */ | 2551 | /* string arguments requiring a lookup */ |
2397 | dump_cfg_string(sLogLevel, log_level_name(o->log_level)); | 2552 | dump_cfg_string(sLogLevel, log_level_name(o->log_level)); |
@@ -2420,11 +2575,13 @@ dump_config(ServerOptions *o) | |||
2420 | printf("maxstartups %d:%d:%d\n", o->max_startups_begin, | 2575 | printf("maxstartups %d:%d:%d\n", o->max_startups_begin, |
2421 | o->max_startups_rate, o->max_startups); | 2576 | o->max_startups_rate, o->max_startups); |
2422 | 2577 | ||
2423 | for (i = 0; tunmode_desc[i].val != -1; i++) | 2578 | s = NULL; |
2579 | for (i = 0; tunmode_desc[i].val != -1; i++) { | ||
2424 | if (tunmode_desc[i].val == o->permit_tun) { | 2580 | if (tunmode_desc[i].val == o->permit_tun) { |
2425 | s = tunmode_desc[i].text; | 2581 | s = tunmode_desc[i].text; |
2426 | break; | 2582 | break; |
2427 | } | 2583 | } |
2584 | } | ||
2428 | dump_cfg_string(sPermitTunnel, s); | 2585 | dump_cfg_string(sPermitTunnel, s); |
2429 | 2586 | ||
2430 | printf("ipqos %s ", iptos2str(o->ip_qos_interactive)); | 2587 | printf("ipqos %s ", iptos2str(o->ip_qos_interactive)); |