diff options
Diffstat (limited to 'servconf.c')
-rw-r--r-- | servconf.c | 567 |
1 files changed, 361 insertions, 206 deletions
diff --git a/servconf.c b/servconf.c index 2c321a4ad..0f0d09068 100644 --- a/servconf.c +++ b/servconf.c | |||
@@ -1,5 +1,5 @@ | |||
1 | 1 | ||
2 | /* $OpenBSD: servconf.c,v 1.312 2017/10/02 19:33:20 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; |
@@ -188,10 +198,45 @@ assemble_algorithms(ServerOptions *o) | |||
188 | fatal("kex_assemble_names failed"); | 198 | fatal("kex_assemble_names failed"); |
189 | } | 199 | } |
190 | 200 | ||
201 | static void | ||
202 | array_append(const char *file, const int line, const char *directive, | ||
203 | char ***array, u_int *lp, const char *s) | ||
204 | { | ||
205 | |||
206 | if (*lp >= INT_MAX) | ||
207 | fatal("%s line %d: Too many %s entries", file, line, directive); | ||
208 | |||
209 | *array = xrecallocarray(*array, *lp, *lp + 1, sizeof(**array)); | ||
210 | (*array)[*lp] = xstrdup(s); | ||
211 | (*lp)++; | ||
212 | } | ||
213 | |||
214 | void | ||
215 | servconf_add_hostkey(const char *file, const int line, | ||
216 | ServerOptions *options, const char *path) | ||
217 | { | ||
218 | char *apath = derelativise_path(path); | ||
219 | |||
220 | array_append(file, line, "HostKey", | ||
221 | &options->host_key_files, &options->num_host_key_files, apath); | ||
222 | free(apath); | ||
223 | } | ||
224 | |||
225 | void | ||
226 | servconf_add_hostcert(const char *file, const int line, | ||
227 | ServerOptions *options, const char *path) | ||
228 | { | ||
229 | char *apath = derelativise_path(path); | ||
230 | |||
231 | array_append(file, line, "HostCertificate", | ||
232 | &options->host_cert_files, &options->num_host_cert_files, apath); | ||
233 | free(apath); | ||
234 | } | ||
235 | |||
191 | void | 236 | void |
192 | fill_default_server_options(ServerOptions *options) | 237 | fill_default_server_options(ServerOptions *options) |
193 | { | 238 | { |
194 | int i; | 239 | u_int i; |
195 | 240 | ||
196 | /* Portable-specific options */ | 241 | /* Portable-specific options */ |
197 | if (options->use_pam == -1) | 242 | if (options->use_pam == -1) |
@@ -200,16 +245,18 @@ fill_default_server_options(ServerOptions *options) | |||
200 | /* Standard Options */ | 245 | /* Standard Options */ |
201 | if (options->num_host_key_files == 0) { | 246 | if (options->num_host_key_files == 0) { |
202 | /* fill default hostkeys for protocols */ | 247 | /* fill default hostkeys for protocols */ |
203 | options->host_key_files[options->num_host_key_files++] = | 248 | servconf_add_hostkey("[default]", 0, options, |
204 | _PATH_HOST_RSA_KEY_FILE; | 249 | _PATH_HOST_RSA_KEY_FILE); |
205 | options->host_key_files[options->num_host_key_files++] = | ||
206 | _PATH_HOST_DSA_KEY_FILE; | ||
207 | #ifdef OPENSSL_HAS_ECC | 250 | #ifdef OPENSSL_HAS_ECC |
208 | options->host_key_files[options->num_host_key_files++] = | 251 | servconf_add_hostkey("[default]", 0, options, |
209 | _PATH_HOST_ECDSA_KEY_FILE; | 252 | _PATH_HOST_ECDSA_KEY_FILE); |
210 | #endif | 253 | #endif |
211 | options->host_key_files[options->num_host_key_files++] = | 254 | servconf_add_hostkey("[default]", 0, options, |
212 | _PATH_HOST_ED25519_KEY_FILE; | 255 | _PATH_HOST_ED25519_KEY_FILE); |
256 | #ifdef WITH_XMSS | ||
257 | servconf_add_hostkey("[default]", 0, options, | ||
258 | _PATH_HOST_XMSS_KEY_FILE); | ||
259 | #endif /* WITH_XMSS */ | ||
213 | } | 260 | } |
214 | /* No certificates by default */ | 261 | /* No certificates by default */ |
215 | if (options->num_ports == 0) | 262 | if (options->num_ports == 0) |
@@ -217,7 +264,7 @@ fill_default_server_options(ServerOptions *options) | |||
217 | if (options->address_family == -1) | 264 | if (options->address_family == -1) |
218 | options->address_family = AF_UNSPEC; | 265 | options->address_family = AF_UNSPEC; |
219 | if (options->listen_addrs == NULL) | 266 | if (options->listen_addrs == NULL) |
220 | add_listen_addr(options, NULL, 0); | 267 | add_listen_addr(options, NULL, NULL, 0); |
221 | if (options->pid_file == NULL) | 268 | if (options->pid_file == NULL) |
222 | options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE); | 269 | options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE); |
223 | if (options->login_grace_time == -1) | 270 | if (options->login_grace_time == -1) |
@@ -313,10 +360,14 @@ fill_default_server_options(ServerOptions *options) | |||
313 | if (options->client_alive_count_max == -1) | 360 | if (options->client_alive_count_max == -1) |
314 | options->client_alive_count_max = 3; | 361 | options->client_alive_count_max = 3; |
315 | if (options->num_authkeys_files == 0) { | 362 | if (options->num_authkeys_files == 0) { |
316 | options->authorized_keys_files[options->num_authkeys_files++] = | 363 | array_append("[default]", 0, "AuthorizedKeysFiles", |
317 | xstrdup(_PATH_SSH_USER_PERMITTED_KEYS); | 364 | &options->authorized_keys_files, |
318 | options->authorized_keys_files[options->num_authkeys_files++] = | 365 | &options->num_authkeys_files, |
319 | xstrdup(_PATH_SSH_USER_PERMITTED_KEYS2); | 366 | _PATH_SSH_USER_PERMITTED_KEYS); |
367 | array_append("[default]", 0, "AuthorizedKeysFiles", | ||
368 | &options->authorized_keys_files, | ||
369 | &options->num_authkeys_files, | ||
370 | _PATH_SSH_USER_PERMITTED_KEYS2); | ||
320 | } | 371 | } |
321 | if (options->permit_tun == -1) | 372 | if (options->permit_tun == -1) |
322 | options->permit_tun = SSH_TUNMODE_NO; | 373 | options->permit_tun = SSH_TUNMODE_NO; |
@@ -358,6 +409,7 @@ fill_default_server_options(ServerOptions *options) | |||
358 | CLEAR_ON_NONE(options->authorized_principals_file); | 409 | CLEAR_ON_NONE(options->authorized_principals_file); |
359 | CLEAR_ON_NONE(options->adm_forced_command); | 410 | CLEAR_ON_NONE(options->adm_forced_command); |
360 | CLEAR_ON_NONE(options->chroot_directory); | 411 | CLEAR_ON_NONE(options->chroot_directory); |
412 | CLEAR_ON_NONE(options->routing_domain); | ||
361 | for (i = 0; i < options->num_host_key_files; i++) | 413 | for (i = 0; i < options->num_host_key_files; i++) |
362 | CLEAR_ON_NONE(options->host_key_files[i]); | 414 | CLEAR_ON_NONE(options->host_key_files[i]); |
363 | for (i = 0; i < options->num_host_cert_files; i++) | 415 | for (i = 0; i < options->num_host_cert_files; i++) |
@@ -393,8 +445,7 @@ typedef enum { | |||
393 | sPermitRootLogin, sLogFacility, sLogLevel, | 445 | sPermitRootLogin, sLogFacility, sLogLevel, |
394 | sRhostsRSAAuthentication, sRSAAuthentication, | 446 | sRhostsRSAAuthentication, sRSAAuthentication, |
395 | sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, | 447 | sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, |
396 | sKerberosGetAFSToken, | 448 | sKerberosGetAFSToken, sChallengeResponseAuthentication, |
397 | sKerberosTgtPassing, sChallengeResponseAuthentication, | ||
398 | sPasswordAuthentication, sKbdInteractiveAuthentication, | 449 | sPasswordAuthentication, sKbdInteractiveAuthentication, |
399 | sListenAddress, sAddressFamily, | 450 | sListenAddress, sAddressFamily, |
400 | sPrintMotd, sPrintLastLog, sIgnoreRhosts, | 451 | sPrintMotd, sPrintLastLog, sIgnoreRhosts, |
@@ -421,7 +472,7 @@ typedef enum { | |||
421 | sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, | 472 | sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, |
422 | sStreamLocalBindMask, sStreamLocalBindUnlink, | 473 | sStreamLocalBindMask, sStreamLocalBindUnlink, |
423 | sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, | 474 | sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, |
424 | sExposeAuthInfo, | 475 | sExposeAuthInfo, sRDomain, |
425 | sDeprecated, sIgnore, sUnsupported | 476 | sDeprecated, sIgnore, sUnsupported |
426 | } ServerOpCodes; | 477 | } ServerOpCodes; |
427 | 478 | ||
@@ -566,6 +617,7 @@ static struct { | |||
566 | { "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL }, | 617 | { "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL }, |
567 | { "disableforwarding", sDisableForwarding, SSHCFG_ALL }, | 618 | { "disableforwarding", sDisableForwarding, SSHCFG_ALL }, |
568 | { "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL }, | 619 | { "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL }, |
620 | { "rdomain", sRDomain, SSHCFG_ALL }, | ||
569 | { NULL, sBadOption, 0 } | 621 | { NULL, sBadOption, 0 } |
570 | }; | 622 | }; |
571 | 623 | ||
@@ -619,23 +671,51 @@ derelativise_path(const char *path) | |||
619 | } | 671 | } |
620 | 672 | ||
621 | static void | 673 | static void |
622 | add_listen_addr(ServerOptions *options, char *addr, int port) | 674 | add_listen_addr(ServerOptions *options, const char *addr, |
675 | const char *rdomain, int port) | ||
623 | { | 676 | { |
624 | u_int i; | 677 | u_int i; |
625 | 678 | ||
626 | if (port == 0) | 679 | if (port > 0) |
627 | for (i = 0; i < options->num_ports; i++) | 680 | add_one_listen_addr(options, addr, rdomain, port); |
628 | add_one_listen_addr(options, addr, options->ports[i]); | 681 | else { |
629 | else | 682 | for (i = 0; i < options->num_ports; i++) { |
630 | add_one_listen_addr(options, addr, port); | 683 | add_one_listen_addr(options, addr, rdomain, |
684 | options->ports[i]); | ||
685 | } | ||
686 | } | ||
631 | } | 687 | } |
632 | 688 | ||
633 | static void | 689 | static void |
634 | add_one_listen_addr(ServerOptions *options, char *addr, int port) | 690 | add_one_listen_addr(ServerOptions *options, const char *addr, |
691 | const char *rdomain, int port) | ||
635 | { | 692 | { |
636 | struct addrinfo hints, *ai, *aitop; | 693 | struct addrinfo hints, *ai, *aitop; |
637 | char strport[NI_MAXSERV]; | 694 | char strport[NI_MAXSERV]; |
638 | int gaierr; | 695 | int gaierr; |
696 | u_int i; | ||
697 | |||
698 | /* Find listen_addrs entry for this rdomain */ | ||
699 | for (i = 0; i < options->num_listen_addrs; i++) { | ||
700 | if (rdomain == NULL && options->listen_addrs[i].rdomain == NULL) | ||
701 | break; | ||
702 | if (rdomain == NULL || options->listen_addrs[i].rdomain == NULL) | ||
703 | continue; | ||
704 | if (strcmp(rdomain, options->listen_addrs[i].rdomain) == 0) | ||
705 | break; | ||
706 | } | ||
707 | if (i >= options->num_listen_addrs) { | ||
708 | /* No entry for this rdomain; allocate one */ | ||
709 | if (i >= INT_MAX) | ||
710 | fatal("%s: too many listen addresses", __func__); | ||
711 | options->listen_addrs = xrecallocarray(options->listen_addrs, | ||
712 | options->num_listen_addrs, options->num_listen_addrs + 1, | ||
713 | sizeof(*options->listen_addrs)); | ||
714 | i = options->num_listen_addrs++; | ||
715 | if (rdomain != NULL) | ||
716 | options->listen_addrs[i].rdomain = xstrdup(rdomain); | ||
717 | } | ||
718 | /* options->listen_addrs[i] points to the addresses for this rdomain */ | ||
639 | 719 | ||
640 | memset(&hints, 0, sizeof(hints)); | 720 | memset(&hints, 0, sizeof(hints)); |
641 | hints.ai_family = options->address_family; | 721 | hints.ai_family = options->address_family; |
@@ -648,8 +728,44 @@ add_one_listen_addr(ServerOptions *options, char *addr, int port) | |||
648 | ssh_gai_strerror(gaierr)); | 728 | ssh_gai_strerror(gaierr)); |
649 | for (ai = aitop; ai->ai_next; ai = ai->ai_next) | 729 | for (ai = aitop; ai->ai_next; ai = ai->ai_next) |
650 | ; | 730 | ; |
651 | ai->ai_next = options->listen_addrs; | 731 | ai->ai_next = options->listen_addrs[i].addrs; |
652 | options->listen_addrs = aitop; | 732 | options->listen_addrs[i].addrs = aitop; |
733 | } | ||
734 | |||
735 | /* Returns nonzero if the routing domain name is valid */ | ||
736 | static int | ||
737 | valid_rdomain(const char *name) | ||
738 | { | ||
739 | #if defined(HAVE_SYS_VALID_RDOMAIN) | ||
740 | return sys_valid_rdomain(name); | ||
741 | #elif defined(__OpenBSD__) | ||
742 | const char *errstr; | ||
743 | long long num; | ||
744 | struct rt_tableinfo info; | ||
745 | int mib[6]; | ||
746 | size_t miblen = sizeof(mib); | ||
747 | |||
748 | if (name == NULL) | ||
749 | return 1; | ||
750 | |||
751 | num = strtonum(name, 0, 255, &errstr); | ||
752 | if (errstr != NULL) | ||
753 | return 0; | ||
754 | |||
755 | /* Check whether the table actually exists */ | ||
756 | memset(mib, 0, sizeof(mib)); | ||
757 | mib[0] = CTL_NET; | ||
758 | mib[1] = PF_ROUTE; | ||
759 | mib[4] = NET_RT_TABLE; | ||
760 | mib[5] = (int)num; | ||
761 | if (sysctl(mib, 6, &info, &miblen, NULL, 0) == -1) | ||
762 | return 0; | ||
763 | |||
764 | return 1; | ||
765 | #else /* defined(__OpenBSD__) */ | ||
766 | error("Routing domains are not supported on this platform"); | ||
767 | return 0; | ||
768 | #endif | ||
653 | } | 769 | } |
654 | 770 | ||
655 | /* | 771 | /* |
@@ -657,18 +773,19 @@ add_one_listen_addr(ServerOptions *options, char *addr, int port) | |||
657 | * and AddressFamily options. | 773 | * and AddressFamily options. |
658 | */ | 774 | */ |
659 | static void | 775 | static void |
660 | queue_listen_addr(ServerOptions *options, char *addr, int port) | 776 | queue_listen_addr(ServerOptions *options, const char *addr, |
777 | const char *rdomain, int port) | ||
661 | { | 778 | { |
662 | options->queued_listen_addrs = xreallocarray( | 779 | struct queued_listenaddr *qla; |
663 | options->queued_listen_addrs, options->num_queued_listens + 1, | 780 | |
664 | sizeof(addr)); | 781 | options->queued_listen_addrs = xrecallocarray( |
665 | options->queued_listen_ports = xreallocarray( | 782 | options->queued_listen_addrs, |
666 | options->queued_listen_ports, options->num_queued_listens + 1, | 783 | options->num_queued_listens, options->num_queued_listens + 1, |
667 | sizeof(port)); | 784 | sizeof(*options->queued_listen_addrs)); |
668 | options->queued_listen_addrs[options->num_queued_listens] = | 785 | qla = &options->queued_listen_addrs[options->num_queued_listens++]; |
669 | xstrdup(addr); | 786 | qla->addr = xstrdup(addr); |
670 | options->queued_listen_ports[options->num_queued_listens] = port; | 787 | qla->port = port; |
671 | options->num_queued_listens++; | 788 | qla->rdomain = rdomain == NULL ? NULL : xstrdup(rdomain); |
672 | } | 789 | } |
673 | 790 | ||
674 | /* | 791 | /* |
@@ -678,6 +795,7 @@ static void | |||
678 | process_queued_listen_addrs(ServerOptions *options) | 795 | process_queued_listen_addrs(ServerOptions *options) |
679 | { | 796 | { |
680 | u_int i; | 797 | u_int i; |
798 | struct queued_listenaddr *qla; | ||
681 | 799 | ||
682 | if (options->num_ports == 0) | 800 | if (options->num_ports == 0) |
683 | options->ports[options->num_ports++] = SSH_DEFAULT_PORT; | 801 | options->ports[options->num_ports++] = SSH_DEFAULT_PORT; |
@@ -685,15 +803,13 @@ process_queued_listen_addrs(ServerOptions *options) | |||
685 | options->address_family = AF_UNSPEC; | 803 | options->address_family = AF_UNSPEC; |
686 | 804 | ||
687 | for (i = 0; i < options->num_queued_listens; i++) { | 805 | for (i = 0; i < options->num_queued_listens; i++) { |
688 | add_listen_addr(options, options->queued_listen_addrs[i], | 806 | qla = &options->queued_listen_addrs[i]; |
689 | options->queued_listen_ports[i]); | 807 | add_listen_addr(options, qla->addr, qla->rdomain, qla->port); |
690 | free(options->queued_listen_addrs[i]); | 808 | free(qla->addr); |
691 | options->queued_listen_addrs[i] = NULL; | 809 | free(qla->rdomain); |
692 | } | 810 | } |
693 | free(options->queued_listen_addrs); | 811 | free(options->queued_listen_addrs); |
694 | options->queued_listen_addrs = NULL; | 812 | options->queued_listen_addrs = NULL; |
695 | free(options->queued_listen_ports); | ||
696 | options->queued_listen_ports = NULL; | ||
697 | options->num_queued_listens = 0; | 813 | options->num_queued_listens = 0; |
698 | } | 814 | } |
699 | 815 | ||
@@ -747,6 +863,7 @@ get_connection_info(int populate, int use_dns) | |||
747 | ci.address = ssh_remote_ipaddr(ssh); | 863 | ci.address = ssh_remote_ipaddr(ssh); |
748 | ci.laddress = ssh_local_ipaddr(ssh); | 864 | ci.laddress = ssh_local_ipaddr(ssh); |
749 | ci.lport = ssh_local_port(ssh); | 865 | ci.lport = ssh_local_port(ssh); |
866 | ci.rdomain = ssh_packet_rdomain_in(ssh); | ||
750 | return &ci; | 867 | return &ci; |
751 | } | 868 | } |
752 | 869 | ||
@@ -811,6 +928,13 @@ out: | |||
811 | return result; | 928 | return result; |
812 | } | 929 | } |
813 | 930 | ||
931 | static void | ||
932 | match_test_missing_fatal(const char *criteria, const char *attrib) | ||
933 | { | ||
934 | fatal("'Match %s' in configuration but '%s' not in connection " | ||
935 | "test specification.", criteria, attrib); | ||
936 | } | ||
937 | |||
814 | /* | 938 | /* |
815 | * All of the attributes on a single Match line are ANDed together, so we need | 939 | * All of the attributes on a single Match line are ANDed together, so we need |
816 | * to check every attribute and set the result to zero if any attribute does | 940 | * to check every attribute and set the result to zero if any attribute does |
@@ -848,20 +972,24 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) | |||
848 | return -1; | 972 | return -1; |
849 | } | 973 | } |
850 | if (strcasecmp(attrib, "user") == 0) { | 974 | if (strcasecmp(attrib, "user") == 0) { |
851 | if (ci == NULL || ci->user == NULL) { | 975 | if (ci == NULL) { |
852 | result = 0; | 976 | result = 0; |
853 | continue; | 977 | continue; |
854 | } | 978 | } |
979 | if (ci->user == NULL) | ||
980 | match_test_missing_fatal("User", "user"); | ||
855 | if (match_pattern_list(ci->user, arg, 0) != 1) | 981 | if (match_pattern_list(ci->user, arg, 0) != 1) |
856 | result = 0; | 982 | result = 0; |
857 | else | 983 | else |
858 | debug("user %.100s matched 'User %.100s' at " | 984 | debug("user %.100s matched 'User %.100s' at " |
859 | "line %d", ci->user, arg, line); | 985 | "line %d", ci->user, arg, line); |
860 | } else if (strcasecmp(attrib, "group") == 0) { | 986 | } else if (strcasecmp(attrib, "group") == 0) { |
861 | if (ci == NULL || ci->user == NULL) { | 987 | if (ci == NULL) { |
862 | result = 0; | 988 | result = 0; |
863 | continue; | 989 | continue; |
864 | } | 990 | } |
991 | if (ci->user == NULL) | ||
992 | match_test_missing_fatal("Group", "user"); | ||
865 | switch (match_cfg_line_group(arg, line, ci->user)) { | 993 | switch (match_cfg_line_group(arg, line, ci->user)) { |
866 | case -1: | 994 | case -1: |
867 | return -1; | 995 | return -1; |
@@ -869,20 +997,24 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) | |||
869 | result = 0; | 997 | result = 0; |
870 | } | 998 | } |
871 | } else if (strcasecmp(attrib, "host") == 0) { | 999 | } else if (strcasecmp(attrib, "host") == 0) { |
872 | if (ci == NULL || ci->host == NULL) { | 1000 | if (ci == NULL) { |
873 | result = 0; | 1001 | result = 0; |
874 | continue; | 1002 | continue; |
875 | } | 1003 | } |
1004 | if (ci->host == NULL) | ||
1005 | match_test_missing_fatal("Host", "host"); | ||
876 | if (match_hostname(ci->host, arg) != 1) | 1006 | if (match_hostname(ci->host, arg) != 1) |
877 | result = 0; | 1007 | result = 0; |
878 | else | 1008 | else |
879 | debug("connection from %.100s matched 'Host " | 1009 | debug("connection from %.100s matched 'Host " |
880 | "%.100s' at line %d", ci->host, arg, line); | 1010 | "%.100s' at line %d", ci->host, arg, line); |
881 | } else if (strcasecmp(attrib, "address") == 0) { | 1011 | } else if (strcasecmp(attrib, "address") == 0) { |
882 | if (ci == NULL || ci->address == NULL) { | 1012 | if (ci == NULL) { |
883 | result = 0; | 1013 | result = 0; |
884 | continue; | 1014 | continue; |
885 | } | 1015 | } |
1016 | if (ci->address == NULL) | ||
1017 | match_test_missing_fatal("Address", "addr"); | ||
886 | switch (addr_match_list(ci->address, arg)) { | 1018 | switch (addr_match_list(ci->address, arg)) { |
887 | case 1: | 1019 | case 1: |
888 | debug("connection from %.100s matched 'Address " | 1020 | debug("connection from %.100s matched 'Address " |
@@ -896,10 +1028,13 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) | |||
896 | return -1; | 1028 | return -1; |
897 | } | 1029 | } |
898 | } else if (strcasecmp(attrib, "localaddress") == 0){ | 1030 | } else if (strcasecmp(attrib, "localaddress") == 0){ |
899 | if (ci == NULL || ci->laddress == NULL) { | 1031 | if (ci == NULL) { |
900 | result = 0; | 1032 | result = 0; |
901 | continue; | 1033 | continue; |
902 | } | 1034 | } |
1035 | if (ci->laddress == NULL) | ||
1036 | match_test_missing_fatal("LocalAddress", | ||
1037 | "laddr"); | ||
903 | switch (addr_match_list(ci->laddress, arg)) { | 1038 | switch (addr_match_list(ci->laddress, arg)) { |
904 | case 1: | 1039 | case 1: |
905 | debug("connection from %.100s matched " | 1040 | debug("connection from %.100s matched " |
@@ -919,10 +1054,12 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) | |||
919 | arg); | 1054 | arg); |
920 | return -1; | 1055 | return -1; |
921 | } | 1056 | } |
922 | if (ci == NULL || ci->lport == 0) { | 1057 | if (ci == NULL) { |
923 | result = 0; | 1058 | result = 0; |
924 | continue; | 1059 | continue; |
925 | } | 1060 | } |
1061 | if (ci->lport == 0) | ||
1062 | match_test_missing_fatal("LocalPort", "lport"); | ||
926 | /* TODO support port lists */ | 1063 | /* TODO support port lists */ |
927 | if (port == ci->lport) | 1064 | if (port == ci->lport) |
928 | debug("connection from %.100s matched " | 1065 | debug("connection from %.100s matched " |
@@ -930,6 +1067,16 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) | |||
930 | ci->laddress, port, line); | 1067 | ci->laddress, port, line); |
931 | else | 1068 | else |
932 | result = 0; | 1069 | result = 0; |
1070 | } else if (strcasecmp(attrib, "rdomain") == 0) { | ||
1071 | if (ci == NULL || ci->rdomain == NULL) { | ||
1072 | result = 0; | ||
1073 | continue; | ||
1074 | } | ||
1075 | if (match_pattern_list(ci->rdomain, arg, 0) != 1) | ||
1076 | result = 0; | ||
1077 | else | ||
1078 | debug("user %.100s matched 'RDomain %.100s' at " | ||
1079 | "line %d", ci->rdomain, arg, line); | ||
933 | } else { | 1080 | } else { |
934 | error("Unsupported Match attribute %s", attrib); | 1081 | error("Unsupported Match attribute %s", attrib); |
935 | return -1; | 1082 | return -1; |
@@ -952,6 +1099,11 @@ struct multistate { | |||
952 | char *key; | 1099 | char *key; |
953 | int value; | 1100 | int value; |
954 | }; | 1101 | }; |
1102 | static const struct multistate multistate_flag[] = { | ||
1103 | { "yes", 1 }, | ||
1104 | { "no", 0 }, | ||
1105 | { NULL, -1 } | ||
1106 | }; | ||
955 | static const struct multistate multistate_addressfamily[] = { | 1107 | static const struct multistate multistate_addressfamily[] = { |
956 | { "inet", AF_INET }, | 1108 | { "inet", AF_INET }, |
957 | { "inet6", AF_INET6 }, | 1109 | { "inet6", AF_INET6 }, |
@@ -1001,6 +1153,7 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1001 | size_t len; | 1153 | size_t len; |
1002 | long long val64; | 1154 | long long val64; |
1003 | const struct multistate *multistate_ptr; | 1155 | const struct multistate *multistate_ptr; |
1156 | const char *errstr; | ||
1004 | 1157 | ||
1005 | /* Strip trailing whitespace. Allow \f (form feed) at EOL only */ | 1158 | /* Strip trailing whitespace. Allow \f (form feed) at EOL only */ |
1006 | if ((len = strlen(line)) == 0) | 1159 | if ((len = strlen(line)) == 0) |
@@ -1088,20 +1241,33 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1088 | /* check for bare IPv6 address: no "[]" and 2 or more ":" */ | 1241 | /* check for bare IPv6 address: no "[]" and 2 or more ":" */ |
1089 | if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL | 1242 | if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL |
1090 | && strchr(p+1, ':') != NULL) { | 1243 | && strchr(p+1, ':') != NULL) { |
1091 | queue_listen_addr(options, arg, 0); | ||
1092 | break; | ||
1093 | } | ||
1094 | p = hpdelim(&arg); | ||
1095 | if (p == NULL) | ||
1096 | fatal("%s line %d: bad address:port usage", | ||
1097 | filename, linenum); | ||
1098 | p = cleanhostname(p); | ||
1099 | if (arg == NULL) | ||
1100 | port = 0; | 1244 | port = 0; |
1101 | else if ((port = a2port(arg)) <= 0) | 1245 | p = arg; |
1102 | fatal("%s line %d: bad port number", filename, linenum); | 1246 | } else { |
1247 | p = hpdelim(&arg); | ||
1248 | if (p == NULL) | ||
1249 | fatal("%s line %d: bad address:port usage", | ||
1250 | filename, linenum); | ||
1251 | p = cleanhostname(p); | ||
1252 | if (arg == NULL) | ||
1253 | port = 0; | ||
1254 | else if ((port = a2port(arg)) <= 0) | ||
1255 | fatal("%s line %d: bad port number", | ||
1256 | filename, linenum); | ||
1257 | } | ||
1258 | /* Optional routing table */ | ||
1259 | arg2 = NULL; | ||
1260 | if ((arg = strdelim(&cp)) != NULL) { | ||
1261 | if (strcmp(arg, "rdomain") != 0 || | ||
1262 | (arg2 = strdelim(&cp)) == NULL) | ||
1263 | fatal("%s line %d: bad ListenAddress syntax", | ||
1264 | filename, linenum); | ||
1265 | if (!valid_rdomain(arg2)) | ||
1266 | fatal("%s line %d: bad routing domain", | ||
1267 | filename, linenum); | ||
1268 | } | ||
1103 | 1269 | ||
1104 | queue_listen_addr(options, p, port); | 1270 | queue_listen_addr(options, p, arg2, port); |
1105 | 1271 | ||
1106 | break; | 1272 | break; |
1107 | 1273 | ||
@@ -1128,22 +1294,12 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1128 | break; | 1294 | break; |
1129 | 1295 | ||
1130 | case sHostKeyFile: | 1296 | case sHostKeyFile: |
1131 | intptr = &options->num_host_key_files; | ||
1132 | if (*intptr >= MAX_HOSTKEYS) | ||
1133 | fatal("%s line %d: too many host keys specified (max %d).", | ||
1134 | filename, linenum, MAX_HOSTKEYS); | ||
1135 | charptr = &options->host_key_files[*intptr]; | ||
1136 | parse_filename: | ||
1137 | arg = strdelim(&cp); | 1297 | arg = strdelim(&cp); |
1138 | if (!arg || *arg == '\0') | 1298 | if (!arg || *arg == '\0') |
1139 | fatal("%s line %d: missing file name.", | 1299 | fatal("%s line %d: missing file name.", |
1140 | filename, linenum); | 1300 | filename, linenum); |
1141 | if (*activep && *charptr == NULL) { | 1301 | if (*activep) |
1142 | *charptr = derelativise_path(arg); | 1302 | servconf_add_hostkey(filename, linenum, options, arg); |
1143 | /* increase optional counter */ | ||
1144 | if (intptr != NULL) | ||
1145 | *intptr = *intptr + 1; | ||
1146 | } | ||
1147 | break; | 1303 | break; |
1148 | 1304 | ||
1149 | case sHostKeyAgent: | 1305 | case sHostKeyAgent: |
@@ -1158,17 +1314,28 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1158 | break; | 1314 | break; |
1159 | 1315 | ||
1160 | case sHostCertificate: | 1316 | case sHostCertificate: |
1161 | intptr = &options->num_host_cert_files; | 1317 | arg = strdelim(&cp); |
1162 | if (*intptr >= MAX_HOSTKEYS) | 1318 | if (!arg || *arg == '\0') |
1163 | fatal("%s line %d: too many host certificates " | 1319 | fatal("%s line %d: missing file name.", |
1164 | "specified (max %d).", filename, linenum, | 1320 | filename, linenum); |
1165 | MAX_HOSTCERTS); | 1321 | if (*activep) |
1166 | charptr = &options->host_cert_files[*intptr]; | 1322 | servconf_add_hostcert(filename, linenum, options, arg); |
1167 | goto parse_filename; | 1323 | break; |
1168 | 1324 | ||
1169 | case sPidFile: | 1325 | case sPidFile: |
1170 | charptr = &options->pid_file; | 1326 | charptr = &options->pid_file; |
1171 | goto parse_filename; | 1327 | parse_filename: |
1328 | arg = strdelim(&cp); | ||
1329 | if (!arg || *arg == '\0') | ||
1330 | fatal("%s line %d: missing file name.", | ||
1331 | filename, linenum); | ||
1332 | if (*activep && *charptr == NULL) { | ||
1333 | *charptr = derelativise_path(arg); | ||
1334 | /* increase optional counter */ | ||
1335 | if (intptr != NULL) | ||
1336 | *intptr = *intptr + 1; | ||
1337 | } | ||
1338 | break; | ||
1172 | 1339 | ||
1173 | case sPermitRootLogin: | 1340 | case sPermitRootLogin: |
1174 | intptr = &options->permit_root_login; | 1341 | intptr = &options->permit_root_login; |
@@ -1178,21 +1345,8 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1178 | case sIgnoreRhosts: | 1345 | case sIgnoreRhosts: |
1179 | intptr = &options->ignore_rhosts; | 1346 | intptr = &options->ignore_rhosts; |
1180 | parse_flag: | 1347 | parse_flag: |
1181 | arg = strdelim(&cp); | 1348 | multistate_ptr = multistate_flag; |
1182 | if (!arg || *arg == '\0') | 1349 | goto parse_multistate; |
1183 | fatal("%s line %d: missing yes/no argument.", | ||
1184 | filename, linenum); | ||
1185 | value = 0; /* silence compiler */ | ||
1186 | if (strcmp(arg, "yes") == 0) | ||
1187 | value = 1; | ||
1188 | else if (strcmp(arg, "no") == 0) | ||
1189 | value = 0; | ||
1190 | else | ||
1191 | fatal("%s line %d: Bad yes/no argument: %s", | ||
1192 | filename, linenum, arg); | ||
1193 | if (*activep && *intptr == -1) | ||
1194 | *intptr = value; | ||
1195 | break; | ||
1196 | 1350 | ||
1197 | case sIgnoreUserKnownHosts: | 1351 | case sIgnoreUserKnownHosts: |
1198 | intptr = &options->ignore_user_known_hosts; | 1352 | intptr = &options->ignore_user_known_hosts; |
@@ -1289,10 +1443,9 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1289 | intptr = &options->x11_display_offset; | 1443 | intptr = &options->x11_display_offset; |
1290 | parse_int: | 1444 | parse_int: |
1291 | arg = strdelim(&cp); | 1445 | arg = strdelim(&cp); |
1292 | if (!arg || *arg == '\0') | 1446 | if ((errstr = atoi_err(arg, &value)) != NULL) |
1293 | fatal("%s line %d: missing integer value.", | 1447 | fatal("%s line %d: integer value %s.", |
1294 | filename, linenum); | 1448 | filename, linenum, errstr); |
1295 | value = atoi(arg); | ||
1296 | if (*activep && *intptr == -1) | 1449 | if (*activep && *intptr == -1) |
1297 | *intptr = value; | 1450 | *intptr = value; |
1298 | break; | 1451 | break; |
@@ -1412,55 +1565,47 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1412 | 1565 | ||
1413 | case sAllowUsers: | 1566 | case sAllowUsers: |
1414 | while ((arg = strdelim(&cp)) && *arg != '\0') { | 1567 | while ((arg = strdelim(&cp)) && *arg != '\0') { |
1415 | if (options->num_allow_users >= MAX_ALLOW_USERS) | ||
1416 | fatal("%s line %d: too many allow users.", | ||
1417 | filename, linenum); | ||
1418 | if (match_user(NULL, NULL, NULL, arg) == -1) | 1568 | if (match_user(NULL, NULL, NULL, arg) == -1) |
1419 | fatal("%s line %d: invalid AllowUsers pattern: " | 1569 | fatal("%s line %d: invalid AllowUsers pattern: " |
1420 | "\"%.100s\"", filename, linenum, arg); | 1570 | "\"%.100s\"", filename, linenum, arg); |
1421 | if (!*activep) | 1571 | if (!*activep) |
1422 | continue; | 1572 | continue; |
1423 | options->allow_users[options->num_allow_users++] = | 1573 | array_append(filename, linenum, "AllowUsers", |
1424 | xstrdup(arg); | 1574 | &options->allow_users, &options->num_allow_users, |
1575 | arg); | ||
1425 | } | 1576 | } |
1426 | break; | 1577 | break; |
1427 | 1578 | ||
1428 | case sDenyUsers: | 1579 | case sDenyUsers: |
1429 | while ((arg = strdelim(&cp)) && *arg != '\0') { | 1580 | while ((arg = strdelim(&cp)) && *arg != '\0') { |
1430 | if (options->num_deny_users >= MAX_DENY_USERS) | ||
1431 | fatal("%s line %d: too many deny users.", | ||
1432 | filename, linenum); | ||
1433 | if (match_user(NULL, NULL, NULL, arg) == -1) | 1581 | if (match_user(NULL, NULL, NULL, arg) == -1) |
1434 | fatal("%s line %d: invalid DenyUsers pattern: " | 1582 | fatal("%s line %d: invalid DenyUsers pattern: " |
1435 | "\"%.100s\"", filename, linenum, arg); | 1583 | "\"%.100s\"", filename, linenum, arg); |
1436 | if (!*activep) | 1584 | if (!*activep) |
1437 | continue; | 1585 | continue; |
1438 | options->deny_users[options->num_deny_users++] = | 1586 | array_append(filename, linenum, "DenyUsers", |
1439 | xstrdup(arg); | 1587 | &options->deny_users, &options->num_deny_users, |
1588 | arg); | ||
1440 | } | 1589 | } |
1441 | break; | 1590 | break; |
1442 | 1591 | ||
1443 | case sAllowGroups: | 1592 | case sAllowGroups: |
1444 | while ((arg = strdelim(&cp)) && *arg != '\0') { | 1593 | while ((arg = strdelim(&cp)) && *arg != '\0') { |
1445 | if (options->num_allow_groups >= MAX_ALLOW_GROUPS) | ||
1446 | fatal("%s line %d: too many allow groups.", | ||
1447 | filename, linenum); | ||
1448 | if (!*activep) | 1594 | if (!*activep) |
1449 | continue; | 1595 | continue; |
1450 | options->allow_groups[options->num_allow_groups++] = | 1596 | array_append(filename, linenum, "AllowGroups", |
1451 | xstrdup(arg); | 1597 | &options->allow_groups, &options->num_allow_groups, |
1598 | arg); | ||
1452 | } | 1599 | } |
1453 | break; | 1600 | break; |
1454 | 1601 | ||
1455 | case sDenyGroups: | 1602 | case sDenyGroups: |
1456 | while ((arg = strdelim(&cp)) && *arg != '\0') { | 1603 | while ((arg = strdelim(&cp)) && *arg != '\0') { |
1457 | if (options->num_deny_groups >= MAX_DENY_GROUPS) | ||
1458 | fatal("%s line %d: too many deny groups.", | ||
1459 | filename, linenum); | ||
1460 | if (!*activep) | 1604 | if (!*activep) |
1461 | continue; | 1605 | continue; |
1462 | options->deny_groups[options->num_deny_groups++] = | 1606 | array_append(filename, linenum, "DenyGroups", |
1463 | xstrdup(arg); | 1607 | &options->deny_groups, &options->num_deny_groups, |
1608 | arg); | ||
1464 | } | 1609 | } |
1465 | break; | 1610 | break; |
1466 | 1611 | ||
@@ -1579,14 +1724,12 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1579 | case sAuthorizedKeysFile: | 1724 | case sAuthorizedKeysFile: |
1580 | if (*activep && options->num_authkeys_files == 0) { | 1725 | if (*activep && options->num_authkeys_files == 0) { |
1581 | while ((arg = strdelim(&cp)) && *arg != '\0') { | 1726 | while ((arg = strdelim(&cp)) && *arg != '\0') { |
1582 | if (options->num_authkeys_files >= | 1727 | arg = tilde_expand_filename(arg, getuid()); |
1583 | MAX_AUTHKEYS_FILES) | 1728 | array_append(filename, linenum, |
1584 | fatal("%s line %d: " | 1729 | "AuthorizedKeysFile", |
1585 | "too many authorized keys files.", | 1730 | &options->authorized_keys_files, |
1586 | filename, linenum); | 1731 | &options->num_authkeys_files, arg); |
1587 | options->authorized_keys_files[ | 1732 | free(arg); |
1588 | options->num_authkeys_files++] = | ||
1589 | tilde_expand_filename(arg, getuid()); | ||
1590 | } | 1733 | } |
1591 | } | 1734 | } |
1592 | return 0; | 1735 | return 0; |
@@ -1618,13 +1761,11 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1618 | if (strchr(arg, '=') != NULL) | 1761 | if (strchr(arg, '=') != NULL) |
1619 | fatal("%s line %d: Invalid environment name.", | 1762 | fatal("%s line %d: Invalid environment name.", |
1620 | filename, linenum); | 1763 | filename, linenum); |
1621 | if (options->num_accept_env >= MAX_ACCEPT_ENV) | ||
1622 | fatal("%s line %d: too many allow env.", | ||
1623 | filename, linenum); | ||
1624 | if (!*activep) | 1764 | if (!*activep) |
1625 | continue; | 1765 | continue; |
1626 | options->accept_env[options->num_accept_env++] = | 1766 | array_append(filename, linenum, "AcceptEnv", |
1627 | xstrdup(arg); | 1767 | &options->accept_env, &options->num_accept_env, |
1768 | arg); | ||
1628 | } | 1769 | } |
1629 | break; | 1770 | break; |
1630 | 1771 | ||
@@ -1663,9 +1804,9 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1663 | if (!arg || *arg == '\0') | 1804 | if (!arg || *arg == '\0') |
1664 | fatal("%s line %d: missing PermitOpen specification", | 1805 | fatal("%s line %d: missing PermitOpen specification", |
1665 | filename, linenum); | 1806 | filename, linenum); |
1666 | i = options->num_permitted_opens; /* modified later */ | 1807 | value = options->num_permitted_opens; /* modified later */ |
1667 | if (strcmp(arg, "any") == 0 || strcmp(arg, "none") == 0) { | 1808 | if (strcmp(arg, "any") == 0 || strcmp(arg, "none") == 0) { |
1668 | if (*activep && i == 0) { | 1809 | if (*activep && value == 0) { |
1669 | options->num_permitted_opens = 1; | 1810 | options->num_permitted_opens = 1; |
1670 | options->permitted_opens = xcalloc(1, | 1811 | options->permitted_opens = xcalloc(1, |
1671 | sizeof(*options->permitted_opens)); | 1812 | sizeof(*options->permitted_opens)); |
@@ -1683,16 +1824,13 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1683 | if (arg == NULL || ((port = permitopen_port(arg)) < 0)) | 1824 | if (arg == NULL || ((port = permitopen_port(arg)) < 0)) |
1684 | fatal("%s line %d: bad port number in " | 1825 | fatal("%s line %d: bad port number in " |
1685 | "PermitOpen", filename, linenum); | 1826 | "PermitOpen", filename, linenum); |
1686 | if (*activep && i == 0) { | 1827 | if (*activep && value == 0) { |
1687 | options->permitted_opens = xrecallocarray( | 1828 | array_append(filename, linenum, |
1688 | options->permitted_opens, | 1829 | "PermitOpen", |
1689 | options->num_permitted_opens, | 1830 | &options->permitted_opens, |
1690 | options->num_permitted_opens + 1, | 1831 | &options->num_permitted_opens, arg2); |
1691 | sizeof(*options->permitted_opens)); | 1832 | } |
1692 | i = options->num_permitted_opens++; | 1833 | free(arg2); |
1693 | options->permitted_opens[i] = arg2; | ||
1694 | } else | ||
1695 | free(arg2); | ||
1696 | } | 1834 | } |
1697 | break; | 1835 | break; |
1698 | 1836 | ||
@@ -1815,11 +1953,6 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1815 | value = 0; /* seen "any" pseudo-method */ | 1953 | value = 0; /* seen "any" pseudo-method */ |
1816 | value2 = 0; /* sucessfully parsed any method */ | 1954 | value2 = 0; /* sucessfully parsed any method */ |
1817 | while ((arg = strdelim(&cp)) && *arg != '\0') { | 1955 | while ((arg = strdelim(&cp)) && *arg != '\0') { |
1818 | if (options->num_auth_methods >= | ||
1819 | MAX_AUTH_METHODS) | ||
1820 | fatal("%s line %d: " | ||
1821 | "too many authentication methods.", | ||
1822 | filename, linenum); | ||
1823 | if (strcmp(arg, "any") == 0) { | 1956 | if (strcmp(arg, "any") == 0) { |
1824 | if (options->num_auth_methods > 0) { | 1957 | if (options->num_auth_methods > 0) { |
1825 | fatal("%s line %d: \"any\" " | 1958 | fatal("%s line %d: \"any\" " |
@@ -1840,8 +1973,10 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1840 | value2 = 1; | 1973 | value2 = 1; |
1841 | if (!*activep) | 1974 | if (!*activep) |
1842 | continue; | 1975 | continue; |
1843 | options->auth_methods[ | 1976 | array_append(filename, linenum, |
1844 | options->num_auth_methods++] = xstrdup(arg); | 1977 | "AuthenticationMethods", |
1978 | &options->auth_methods, | ||
1979 | &options->num_auth_methods, arg); | ||
1845 | } | 1980 | } |
1846 | if (value2 == 0) { | 1981 | if (value2 == 0) { |
1847 | fatal("%s line %d: no AuthenticationMethods " | 1982 | fatal("%s line %d: no AuthenticationMethods " |
@@ -1883,6 +2018,20 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1883 | intptr = &options->expose_userauth_info; | 2018 | intptr = &options->expose_userauth_info; |
1884 | goto parse_flag; | 2019 | goto parse_flag; |
1885 | 2020 | ||
2021 | case sRDomain: | ||
2022 | charptr = &options->routing_domain; | ||
2023 | arg = strdelim(&cp); | ||
2024 | if (!arg || *arg == '\0') | ||
2025 | fatal("%.200s line %d: Missing argument.", | ||
2026 | filename, linenum); | ||
2027 | if (strcasecmp(arg, "none") != 0 && strcmp(arg, "%D") != 0 && | ||
2028 | !valid_rdomain(arg)) | ||
2029 | fatal("%s line %d: bad routing domain", | ||
2030 | filename, linenum); | ||
2031 | if (*activep && *charptr == NULL) | ||
2032 | *charptr = xstrdup(arg); | ||
2033 | break; | ||
2034 | |||
1886 | case sDeprecated: | 2035 | case sDeprecated: |
1887 | case sIgnore: | 2036 | case sIgnore: |
1888 | case sUnsupported: | 2037 | case sUnsupported: |
@@ -1963,6 +2112,8 @@ int parse_server_match_testspec(struct connection_info *ci, char *spec) | |||
1963 | ci->user = xstrdup(p + 5); | 2112 | ci->user = xstrdup(p + 5); |
1964 | } else if (strncmp(p, "laddr=", 6) == 0) { | 2113 | } else if (strncmp(p, "laddr=", 6) == 0) { |
1965 | ci->laddress = xstrdup(p + 6); | 2114 | ci->laddress = xstrdup(p + 6); |
2115 | } else if (strncmp(p, "rdomain=", 8) == 0) { | ||
2116 | ci->rdomain = xstrdup(p + 8); | ||
1966 | } else if (strncmp(p, "lport=", 6) == 0) { | 2117 | } else if (strncmp(p, "lport=", 6) == 0) { |
1967 | ci->lport = a2port(p + 6); | 2118 | ci->lport = a2port(p + 6); |
1968 | if (ci->lport == -1) { | 2119 | if (ci->lport == -1) { |
@@ -1980,19 +2131,6 @@ int parse_server_match_testspec(struct connection_info *ci, char *spec) | |||
1980 | } | 2131 | } |
1981 | 2132 | ||
1982 | /* | 2133 | /* |
1983 | * returns 1 for a complete spec, 0 for partial spec and -1 for an | ||
1984 | * empty spec. | ||
1985 | */ | ||
1986 | int server_match_spec_complete(struct connection_info *ci) | ||
1987 | { | ||
1988 | if (ci->user && ci->host && ci->address) | ||
1989 | return 1; /* complete */ | ||
1990 | if (!ci->user && !ci->host && !ci->address) | ||
1991 | return -1; /* empty */ | ||
1992 | return 0; /* partial */ | ||
1993 | } | ||
1994 | |||
1995 | /* | ||
1996 | * Copy any supported values that are set. | 2134 | * Copy any supported values that are set. |
1997 | * | 2135 | * |
1998 | * If the preauth flag is set, we do not bother copying the string or | 2136 | * If the preauth flag is set, we do not bother copying the string or |
@@ -2057,17 +2195,16 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) | |||
2057 | dst->n = src->n; \ | 2195 | dst->n = src->n; \ |
2058 | } \ | 2196 | } \ |
2059 | } while(0) | 2197 | } while(0) |
2060 | #define M_CP_STRARRAYOPT(n, num_n) do {\ | 2198 | #define M_CP_STRARRAYOPT(s, num_s) do {\ |
2061 | if (src->num_n != 0) { \ | 2199 | u_int i; \ |
2062 | for (dst->num_n = 0; dst->num_n < src->num_n; dst->num_n++) \ | 2200 | if (src->num_s != 0) { \ |
2063 | dst->n[dst->num_n] = xstrdup(src->n[dst->num_n]); \ | 2201 | for (i = 0; i < dst->num_s; i++) \ |
2064 | } \ | 2202 | free(dst->s[i]); \ |
2065 | } while(0) | 2203 | free(dst->s); \ |
2066 | #define M_CP_STRARRAYOPT_ALLOC(n, num_n) do { \ | 2204 | dst->s = xcalloc(src->num_s, sizeof(*dst->s)); \ |
2067 | if (src->num_n != 0) { \ | 2205 | for (i = 0; i < src->num_s; i++) \ |
2068 | dst->n = xcalloc(src->num_n, sizeof(*dst->n)); \ | 2206 | dst->s[i] = xstrdup(src->s[i]); \ |
2069 | M_CP_STRARRAYOPT(n, num_n); \ | 2207 | dst->num_s = src->num_s; \ |
2070 | dst->num_n = src->num_n; \ | ||
2071 | } \ | 2208 | } \ |
2072 | } while(0) | 2209 | } while(0) |
2073 | 2210 | ||
@@ -2100,7 +2237,6 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) | |||
2100 | #undef M_CP_INTOPT | 2237 | #undef M_CP_INTOPT |
2101 | #undef M_CP_STROPT | 2238 | #undef M_CP_STROPT |
2102 | #undef M_CP_STRARRAYOPT | 2239 | #undef M_CP_STRARRAYOPT |
2103 | #undef M_CP_STRARRAYOPT_ALLOC | ||
2104 | 2240 | ||
2105 | void | 2241 | void |
2106 | parse_server_config(ServerOptions *options, const char *filename, Buffer *conf, | 2242 | parse_server_config(ServerOptions *options, const char *filename, Buffer *conf, |
@@ -2231,45 +2367,61 @@ dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals) | |||
2231 | printf("\n"); | 2367 | printf("\n"); |
2232 | } | 2368 | } |
2233 | 2369 | ||
2234 | void | 2370 | static char * |
2235 | dump_config(ServerOptions *o) | 2371 | format_listen_addrs(struct listenaddr *la) |
2236 | { | 2372 | { |
2237 | u_int i; | 2373 | int r; |
2238 | int ret; | ||
2239 | struct addrinfo *ai; | 2374 | struct addrinfo *ai; |
2240 | char addr[NI_MAXHOST], port[NI_MAXSERV], *s = NULL; | 2375 | char addr[NI_MAXHOST], port[NI_MAXSERV]; |
2241 | char *laddr1 = xstrdup(""), *laddr2 = NULL; | 2376 | char *laddr1 = xstrdup(""), *laddr2 = NULL; |
2242 | 2377 | ||
2243 | /* these are usually at the top of the config */ | ||
2244 | for (i = 0; i < o->num_ports; i++) | ||
2245 | printf("port %d\n", o->ports[i]); | ||
2246 | dump_cfg_fmtint(sAddressFamily, o->address_family); | ||
2247 | |||
2248 | /* | 2378 | /* |
2249 | * ListenAddress must be after Port. add_one_listen_addr pushes | 2379 | * ListenAddress must be after Port. add_one_listen_addr pushes |
2250 | * addresses onto a stack, so to maintain ordering we need to | 2380 | * addresses onto a stack, so to maintain ordering we need to |
2251 | * print these in reverse order. | 2381 | * print these in reverse order. |
2252 | */ | 2382 | */ |
2253 | for (ai = o->listen_addrs; ai; ai = ai->ai_next) { | 2383 | for (ai = la->addrs; ai; ai = ai->ai_next) { |
2254 | if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr, | 2384 | if ((r = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr, |
2255 | sizeof(addr), port, sizeof(port), | 2385 | sizeof(addr), port, sizeof(port), |
2256 | NI_NUMERICHOST|NI_NUMERICSERV)) != 0) { | 2386 | NI_NUMERICHOST|NI_NUMERICSERV)) != 0) { |
2257 | error("getnameinfo failed: %.100s", | 2387 | error("getnameinfo: %.100s", ssh_gai_strerror(r)); |
2258 | (ret != EAI_SYSTEM) ? gai_strerror(ret) : | 2388 | continue; |
2259 | strerror(errno)); | 2389 | } |
2390 | laddr2 = laddr1; | ||
2391 | if (ai->ai_family == AF_INET6) { | ||
2392 | xasprintf(&laddr1, "listenaddress [%s]:%s%s%s\n%s", | ||
2393 | addr, port, | ||
2394 | la->rdomain == NULL ? "" : " rdomain ", | ||
2395 | la->rdomain == NULL ? "" : la->rdomain, | ||
2396 | laddr2); | ||
2260 | } else { | 2397 | } else { |
2261 | laddr2 = laddr1; | 2398 | xasprintf(&laddr1, "listenaddress %s:%s%s%s\n%s", |
2262 | if (ai->ai_family == AF_INET6) | 2399 | addr, port, |
2263 | xasprintf(&laddr1, "listenaddress [%s]:%s\n%s", | 2400 | la->rdomain == NULL ? "" : " rdomain ", |
2264 | addr, port, laddr2); | 2401 | la->rdomain == NULL ? "" : la->rdomain, |
2265 | else | 2402 | laddr2); |
2266 | xasprintf(&laddr1, "listenaddress %s:%s\n%s", | ||
2267 | addr, port, laddr2); | ||
2268 | free(laddr2); | ||
2269 | } | 2403 | } |
2404 | free(laddr2); | ||
2405 | } | ||
2406 | return laddr1; | ||
2407 | } | ||
2408 | |||
2409 | void | ||
2410 | dump_config(ServerOptions *o) | ||
2411 | { | ||
2412 | char *s; | ||
2413 | u_int i; | ||
2414 | |||
2415 | /* these are usually at the top of the config */ | ||
2416 | for (i = 0; i < o->num_ports; i++) | ||
2417 | printf("port %d\n", o->ports[i]); | ||
2418 | dump_cfg_fmtint(sAddressFamily, o->address_family); | ||
2419 | |||
2420 | for (i = 0; i < o->num_listen_addrs; i++) { | ||
2421 | s = format_listen_addrs(&o->listen_addrs[i]); | ||
2422 | printf("%s", s); | ||
2423 | free(s); | ||
2270 | } | 2424 | } |
2271 | printf("%s", laddr1); | ||
2272 | free(laddr1); | ||
2273 | 2425 | ||
2274 | /* integer arguments */ | 2426 | /* integer arguments */ |
2275 | #ifdef USE_PAM | 2427 | #ifdef USE_PAM |
@@ -2358,6 +2510,7 @@ dump_config(ServerOptions *o) | |||
2358 | o->hostkeyalgorithms : KEX_DEFAULT_PK_ALG); | 2510 | o->hostkeyalgorithms : KEX_DEFAULT_PK_ALG); |
2359 | dump_cfg_string(sPubkeyAcceptedKeyTypes, o->pubkey_key_types ? | 2511 | dump_cfg_string(sPubkeyAcceptedKeyTypes, o->pubkey_key_types ? |
2360 | o->pubkey_key_types : KEX_DEFAULT_PK_ALG); | 2512 | o->pubkey_key_types : KEX_DEFAULT_PK_ALG); |
2513 | dump_cfg_string(sRDomain, o->routing_domain); | ||
2361 | 2514 | ||
2362 | /* string arguments requiring a lookup */ | 2515 | /* string arguments requiring a lookup */ |
2363 | dump_cfg_string(sLogLevel, log_level_name(o->log_level)); | 2516 | dump_cfg_string(sLogLevel, log_level_name(o->log_level)); |
@@ -2386,11 +2539,13 @@ dump_config(ServerOptions *o) | |||
2386 | printf("maxstartups %d:%d:%d\n", o->max_startups_begin, | 2539 | printf("maxstartups %d:%d:%d\n", o->max_startups_begin, |
2387 | o->max_startups_rate, o->max_startups); | 2540 | o->max_startups_rate, o->max_startups); |
2388 | 2541 | ||
2389 | for (i = 0; tunmode_desc[i].val != -1; i++) | 2542 | s = NULL; |
2543 | for (i = 0; tunmode_desc[i].val != -1; i++) { | ||
2390 | if (tunmode_desc[i].val == o->permit_tun) { | 2544 | if (tunmode_desc[i].val == o->permit_tun) { |
2391 | s = tunmode_desc[i].text; | 2545 | s = tunmode_desc[i].text; |
2392 | break; | 2546 | break; |
2393 | } | 2547 | } |
2548 | } | ||
2394 | dump_cfg_string(sPermitTunnel, s); | 2549 | dump_cfg_string(sPermitTunnel, s); |
2395 | 2550 | ||
2396 | printf("ipqos %s ", iptos2str(o->ip_qos_interactive)); | 2551 | printf("ipqos %s ", iptos2str(o->ip_qos_interactive)); |