summaryrefslogtreecommitdiff
path: root/servconf.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2017-10-25 00:15:35 +0000
committerDamien Miller <djm@mindrot.org>2017-10-25 12:26:06 +1100
commitacf559e1cffbd1d6167cc1742729fc381069f06b (patch)
treefc127e0bce21056c96dec59ebdc9e2ff9f5b1e4a /servconf.c
parentb9903ee8ee8671b447fc260c2bee3761e26c7227 (diff)
upstream commit
Add optional rdomain qualifier to sshd_config's ListenAddress option to allow listening on a different rdomain(4), e.g. ListenAddress 0.0.0.0 rdomain 4 Upstream-ID: 24b6622c376feeed9e9be8b9605e593695ac9091
Diffstat (limited to 'servconf.c')
-rw-r--r--servconf.c229
1 files changed, 162 insertions, 67 deletions
diff --git a/servconf.c b/servconf.c
index a96df4f67..68db047f2 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,5 +1,5 @@
1 1
2/* $OpenBSD: servconf.c,v 1.314 2017/10/05 15:52:03 djm Exp $ */ 2/* $OpenBSD: servconf.c,v 1.315 2017/10/25 00:15:35 djm 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
61static void add_listen_addr(ServerOptions *, char *, int); 67static void add_listen_addr(ServerOptions *, const char *,
62static void add_one_listen_addr(ServerOptions *, char *, int); 68 const char *, int);
69static 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 */
65extern int use_privsep; 73extern int use_privsep;
@@ -81,6 +89,7 @@ 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;
85 options->num_host_key_files = 0; 94 options->num_host_key_files = 0;
86 options->num_host_cert_files = 0; 95 options->num_host_cert_files = 0;
@@ -252,7 +261,7 @@ fill_default_server_options(ServerOptions *options)
252 if (options->address_family == -1) 261 if (options->address_family == -1)
253 options->address_family = AF_UNSPEC; 262 options->address_family = AF_UNSPEC;
254 if (options->listen_addrs == NULL) 263 if (options->listen_addrs == NULL)
255 add_listen_addr(options, NULL, 0); 264 add_listen_addr(options, NULL, NULL, 0);
256 if (options->pid_file == NULL) 265 if (options->pid_file == NULL)
257 options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE); 266 options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE);
258 if (options->login_grace_time == -1) 267 if (options->login_grace_time == -1)
@@ -658,23 +667,51 @@ derelativise_path(const char *path)
658} 667}
659 668
660static void 669static void
661add_listen_addr(ServerOptions *options, char *addr, int port) 670add_listen_addr(ServerOptions *options, const char *addr,
671 const char *rdomain, int port)
662{ 672{
663 u_int i; 673 u_int i;
664 674
665 if (port == 0) 675 if (port > 0)
666 for (i = 0; i < options->num_ports; i++) 676 add_one_listen_addr(options, addr, rdomain, port);
667 add_one_listen_addr(options, addr, options->ports[i]); 677 else {
668 else 678 for (i = 0; i < options->num_ports; i++) {
669 add_one_listen_addr(options, addr, port); 679 add_one_listen_addr(options, addr, rdomain,
680 options->ports[i]);
681 }
682 }
670} 683}
671 684
672static void 685static void
673add_one_listen_addr(ServerOptions *options, char *addr, int port) 686add_one_listen_addr(ServerOptions *options, const char *addr,
687 const char *rdomain, int port)
674{ 688{
675 struct addrinfo hints, *ai, *aitop; 689 struct addrinfo hints, *ai, *aitop;
676 char strport[NI_MAXSERV]; 690 char strport[NI_MAXSERV];
677 int gaierr; 691 int gaierr;
692 u_int i;
693
694 /* Find listen_addrs entry for this rdomain */
695 for (i = 0; i < options->num_listen_addrs; i++) {
696 if (rdomain == NULL && options->listen_addrs[i].rdomain == NULL)
697 break;
698 if (rdomain == NULL || options->listen_addrs[i].rdomain == NULL)
699 continue;
700 if (strcmp(rdomain, options->listen_addrs[i].rdomain) == 0)
701 break;
702 }
703 if (i >= options->num_listen_addrs) {
704 /* No entry for this rdomain; allocate one */
705 if (i >= INT_MAX)
706 fatal("%s: too many listen addresses", __func__);
707 options->listen_addrs = xrecallocarray(options->listen_addrs,
708 options->num_listen_addrs, options->num_listen_addrs + 1,
709 sizeof(*options->listen_addrs));
710 i = options->num_listen_addrs++;
711 if (rdomain != NULL)
712 options->listen_addrs[i].rdomain = xstrdup(rdomain);
713 }
714 /* options->listen_addrs[i] points to the addresses for this rdomain */
678 715
679 memset(&hints, 0, sizeof(hints)); 716 memset(&hints, 0, sizeof(hints));
680 hints.ai_family = options->address_family; 717 hints.ai_family = options->address_family;
@@ -687,8 +724,37 @@ add_one_listen_addr(ServerOptions *options, char *addr, int port)
687 ssh_gai_strerror(gaierr)); 724 ssh_gai_strerror(gaierr));
688 for (ai = aitop; ai->ai_next; ai = ai->ai_next) 725 for (ai = aitop; ai->ai_next; ai = ai->ai_next)
689 ; 726 ;
690 ai->ai_next = options->listen_addrs; 727 ai->ai_next = options->listen_addrs[i].addrs;
691 options->listen_addrs = aitop; 728 options->listen_addrs[i].addrs = aitop;
729}
730
731/* Returns nonzero if the routing domain name is valid */
732static int
733valid_rdomain(const char *name)
734{
735 const char *errstr;
736 long long num;
737 struct rt_tableinfo info;
738 int mib[6];
739 size_t miblen = sizeof(mib);
740
741 if (name == NULL)
742 return 1;
743
744 num = strtonum(name, 0, 255, &errstr);
745 if (errstr != NULL)
746 return 0;
747
748 /* Check whether the table actually exists */
749 memset(mib, 0, sizeof(mib));
750 mib[0] = CTL_NET;
751 mib[1] = PF_ROUTE;
752 mib[4] = NET_RT_TABLE;
753 mib[5] = (int)num;
754 if (sysctl(mib, 6, &info, &miblen, NULL, 0) == -1)
755 return 0;
756
757 return 1;
692} 758}
693 759
694/* 760/*
@@ -696,18 +762,19 @@ add_one_listen_addr(ServerOptions *options, char *addr, int port)
696 * and AddressFamily options. 762 * and AddressFamily options.
697 */ 763 */
698static void 764static void
699queue_listen_addr(ServerOptions *options, char *addr, int port) 765queue_listen_addr(ServerOptions *options, const char *addr,
766 const char *rdomain, int port)
700{ 767{
701 options->queued_listen_addrs = xreallocarray( 768 struct queued_listenaddr *qla;
702 options->queued_listen_addrs, options->num_queued_listens + 1, 769
703 sizeof(addr)); 770 options->queued_listen_addrs = xrecallocarray(
704 options->queued_listen_ports = xreallocarray( 771 options->queued_listen_addrs,
705 options->queued_listen_ports, options->num_queued_listens + 1, 772 options->num_queued_listens, options->num_queued_listens + 1,
706 sizeof(port)); 773 sizeof(*options->queued_listen_addrs));
707 options->queued_listen_addrs[options->num_queued_listens] = 774 qla = &options->queued_listen_addrs[options->num_queued_listens++];
708 xstrdup(addr); 775 qla->addr = xstrdup(addr);
709 options->queued_listen_ports[options->num_queued_listens] = port; 776 qla->port = port;
710 options->num_queued_listens++; 777 qla->rdomain = rdomain == NULL ? NULL : xstrdup(rdomain);
711} 778}
712 779
713/* 780/*
@@ -717,6 +784,7 @@ static void
717process_queued_listen_addrs(ServerOptions *options) 784process_queued_listen_addrs(ServerOptions *options)
718{ 785{
719 u_int i; 786 u_int i;
787 struct queued_listenaddr *qla;
720 788
721 if (options->num_ports == 0) 789 if (options->num_ports == 0)
722 options->ports[options->num_ports++] = SSH_DEFAULT_PORT; 790 options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
@@ -724,15 +792,13 @@ process_queued_listen_addrs(ServerOptions *options)
724 options->address_family = AF_UNSPEC; 792 options->address_family = AF_UNSPEC;
725 793
726 for (i = 0; i < options->num_queued_listens; i++) { 794 for (i = 0; i < options->num_queued_listens; i++) {
727 add_listen_addr(options, options->queued_listen_addrs[i], 795 qla = &options->queued_listen_addrs[i];
728 options->queued_listen_ports[i]); 796 add_listen_addr(options, qla->addr, qla->rdomain, qla->port);
729 free(options->queued_listen_addrs[i]); 797 free(qla->addr);
730 options->queued_listen_addrs[i] = NULL; 798 free(qla->rdomain);
731 } 799 }
732 free(options->queued_listen_addrs); 800 free(options->queued_listen_addrs);
733 options->queued_listen_addrs = NULL; 801 options->queued_listen_addrs = NULL;
734 free(options->queued_listen_ports);
735 options->queued_listen_ports = NULL;
736 options->num_queued_listens = 0; 802 options->num_queued_listens = 0;
737} 803}
738 804
@@ -1127,20 +1193,33 @@ process_server_config_line(ServerOptions *options, char *line,
1127 /* check for bare IPv6 address: no "[]" and 2 or more ":" */ 1193 /* check for bare IPv6 address: no "[]" and 2 or more ":" */
1128 if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL 1194 if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL
1129 && strchr(p+1, ':') != NULL) { 1195 && strchr(p+1, ':') != NULL) {
1130 queue_listen_addr(options, arg, 0);
1131 break;
1132 }
1133 p = hpdelim(&arg);
1134 if (p == NULL)
1135 fatal("%s line %d: bad address:port usage",
1136 filename, linenum);
1137 p = cleanhostname(p);
1138 if (arg == NULL)
1139 port = 0; 1196 port = 0;
1140 else if ((port = a2port(arg)) <= 0) 1197 p = arg;
1141 fatal("%s line %d: bad port number", filename, linenum); 1198 } else {
1199 p = hpdelim(&arg);
1200 if (p == NULL)
1201 fatal("%s line %d: bad address:port usage",
1202 filename, linenum);
1203 p = cleanhostname(p);
1204 if (arg == NULL)
1205 port = 0;
1206 else if ((port = a2port(arg)) <= 0)
1207 fatal("%s line %d: bad port number",
1208 filename, linenum);
1209 }
1210 /* Optional routing table */
1211 arg2 = NULL;
1212 if ((arg = strdelim(&cp)) != NULL) {
1213 if (strcmp(arg, "rdomain") != 0 ||
1214 (arg2 = strdelim(&cp)) == NULL)
1215 fatal("%s line %d: bad ListenAddress syntax",
1216 filename, linenum);
1217 if (!valid_rdomain(arg2))
1218 fatal("%s line %d: bad routing domain",
1219 filename, linenum);
1220 }
1142 1221
1143 queue_listen_addr(options, p, port); 1222 queue_listen_addr(options, p, arg2, port);
1144 1223
1145 break; 1224 break;
1146 1225
@@ -2251,45 +2330,61 @@ dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals)
2251 printf("\n"); 2330 printf("\n");
2252} 2331}
2253 2332
2254void 2333static char *
2255dump_config(ServerOptions *o) 2334format_listen_addrs(struct listenaddr *la)
2256{ 2335{
2257 u_int i; 2336 int r;
2258 int ret;
2259 struct addrinfo *ai; 2337 struct addrinfo *ai;
2260 char addr[NI_MAXHOST], port[NI_MAXSERV], *s = NULL; 2338 char addr[NI_MAXHOST], port[NI_MAXSERV];
2261 char *laddr1 = xstrdup(""), *laddr2 = NULL; 2339 char *laddr1 = xstrdup(""), *laddr2 = NULL;
2262 2340
2263 /* these are usually at the top of the config */
2264 for (i = 0; i < o->num_ports; i++)
2265 printf("port %d\n", o->ports[i]);
2266 dump_cfg_fmtint(sAddressFamily, o->address_family);
2267
2268 /* 2341 /*
2269 * ListenAddress must be after Port. add_one_listen_addr pushes 2342 * ListenAddress must be after Port. add_one_listen_addr pushes
2270 * addresses onto a stack, so to maintain ordering we need to 2343 * addresses onto a stack, so to maintain ordering we need to
2271 * print these in reverse order. 2344 * print these in reverse order.
2272 */ 2345 */
2273 for (ai = o->listen_addrs; ai; ai = ai->ai_next) { 2346 for (ai = la->addrs; ai; ai = ai->ai_next) {
2274 if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr, 2347 if ((r = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
2275 sizeof(addr), port, sizeof(port), 2348 sizeof(addr), port, sizeof(port),
2276 NI_NUMERICHOST|NI_NUMERICSERV)) != 0) { 2349 NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
2277 error("getnameinfo failed: %.100s", 2350 error("getnameinfo: %.100s", ssh_gai_strerror(r));
2278 (ret != EAI_SYSTEM) ? gai_strerror(ret) : 2351 continue;
2279 strerror(errno)); 2352 }
2353 laddr2 = laddr1;
2354 if (ai->ai_family == AF_INET6) {
2355 xasprintf(&laddr1, "listenaddress [%s]:%s%s%s\n%s",
2356 addr, port,
2357 la->rdomain == NULL ? "" : " rdomain ",
2358 la->rdomain == NULL ? "" : la->rdomain,
2359 laddr2);
2280 } else { 2360 } else {
2281 laddr2 = laddr1; 2361 xasprintf(&laddr1, "listenaddress %s:%s%s%s\n%s",
2282 if (ai->ai_family == AF_INET6) 2362 addr, port,
2283 xasprintf(&laddr1, "listenaddress [%s]:%s\n%s", 2363 la->rdomain == NULL ? "" : " rdomain ",
2284 addr, port, laddr2); 2364 la->rdomain == NULL ? "" : la->rdomain,
2285 else 2365 laddr2);
2286 xasprintf(&laddr1, "listenaddress %s:%s\n%s",
2287 addr, port, laddr2);
2288 free(laddr2);
2289 } 2366 }
2367 free(laddr2);
2368 }
2369 return laddr1;
2370}
2371
2372void
2373dump_config(ServerOptions *o)
2374{
2375 char *s;
2376 u_int i;
2377
2378 /* these are usually at the top of the config */
2379 for (i = 0; i < o->num_ports; i++)
2380 printf("port %d\n", o->ports[i]);
2381 dump_cfg_fmtint(sAddressFamily, o->address_family);
2382
2383 for (i = 0; i < o->num_listen_addrs; i++) {
2384 s = format_listen_addrs(&o->listen_addrs[i]);
2385 printf("%s", s);
2386 free(s);
2290 } 2387 }
2291 printf("%s", laddr1);
2292 free(laddr1);
2293 2388
2294 /* integer arguments */ 2389 /* integer arguments */
2295#ifdef USE_PAM 2390#ifdef USE_PAM