summaryrefslogtreecommitdiff
path: root/servconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'servconf.c')
-rw-r--r--servconf.c163
1 files changed, 135 insertions, 28 deletions
diff --git a/servconf.c b/servconf.c
index a8a40f97e..12f43c91e 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,4 +1,5 @@
1/* $OpenBSD: servconf.c,v 1.225 2012/04/12 02:42:32 djm Exp $ */ 1
2/* $OpenBSD: servconf.c,v 1.226 2012/05/13 01:42:32 dtucker Exp $ */
2/* 3/*
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 * All rights reserved 5 * All rights reserved
@@ -45,6 +46,8 @@
45#include "match.h" 46#include "match.h"
46#include "channels.h" 47#include "channels.h"
47#include "groupaccess.h" 48#include "groupaccess.h"
49#include "canohost.h"
50#include "packet.h"
48 51
49static void add_listen_addr(ServerOptions *, char *, int); 52static void add_listen_addr(ServerOptions *, char *, int);
50static void add_one_listen_addr(ServerOptions *, char *, int); 53static void add_one_listen_addr(ServerOptions *, char *, int);
@@ -539,6 +542,20 @@ add_one_listen_addr(ServerOptions *options, char *addr, int port)
539 options->listen_addrs = aitop; 542 options->listen_addrs = aitop;
540} 543}
541 544
545struct connection_info *
546get_connection_info(int populate, int use_dns)
547{
548 static struct connection_info ci;
549
550 if (!populate)
551 return &ci;
552 ci.host = get_canonical_hostname(use_dns);
553 ci.address = get_remote_ipaddr();
554 ci.laddress = get_local_ipaddr(packet_get_connection_in());
555 ci.lport = get_local_port();
556 return &ci;
557}
558
542/* 559/*
543 * The strategy for the Match blocks is that the config file is parsed twice. 560 * The strategy for the Match blocks is that the config file is parsed twice.
544 * 561 *
@@ -600,20 +617,25 @@ out:
600 return result; 617 return result;
601} 618}
602 619
620/*
621 * All of the attributes on a single Match line are ANDed together, so we need to check every
622 * attribute and set the result to zero if any attribute does not match.
623 */
603static int 624static int
604match_cfg_line(char **condition, int line, const char *user, const char *host, 625match_cfg_line(char **condition, int line, struct connection_info *ci)
605 const char *address)
606{ 626{
607 int result = 1; 627 int result = 1, port;
608 char *arg, *attrib, *cp = *condition; 628 char *arg, *attrib, *cp = *condition;
609 size_t len; 629 size_t len;
610 630
611 if (user == NULL) 631 if (ci == NULL)
612 debug3("checking syntax for 'Match %s'", cp); 632 debug3("checking syntax for 'Match %s'", cp);
613 else 633 else
614 debug3("checking match for '%s' user %s host %s addr %s", cp, 634 debug3("checking match for '%s' user %s host %s addr %s "
615 user ? user : "(null)", host ? host : "(null)", 635 "laddr %s lport %d", cp, ci->user ? ci->user : "(null)",
616 address ? address : "(null)"); 636 ci->host ? ci->host : "(null)",
637 ci->address ? ci->address : "(null)",
638 ci->laddress ? ci->laddress : "(null)", ci->lport);
617 639
618 while ((attrib = strdelim(&cp)) && *attrib != '\0') { 640 while ((attrib = strdelim(&cp)) && *attrib != '\0') {
619 if ((arg = strdelim(&cp)) == NULL || *arg == '\0') { 641 if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
@@ -622,37 +644,45 @@ match_cfg_line(char **condition, int line, const char *user, const char *host,
622 } 644 }
623 len = strlen(arg); 645 len = strlen(arg);
624 if (strcasecmp(attrib, "user") == 0) { 646 if (strcasecmp(attrib, "user") == 0) {
625 if (!user) { 647 if (ci == NULL || ci->user == NULL) {
626 result = 0; 648 result = 0;
627 continue; 649 continue;
628 } 650 }
629 if (match_pattern_list(user, arg, len, 0) != 1) 651 if (match_pattern_list(ci->user, arg, len, 0) != 1)
630 result = 0; 652 result = 0;
631 else 653 else
632 debug("user %.100s matched 'User %.100s' at " 654 debug("user %.100s matched 'User %.100s' at "
633 "line %d", user, arg, line); 655 "line %d", ci->user, arg, line);
634 } else if (strcasecmp(attrib, "group") == 0) { 656 } else if (strcasecmp(attrib, "group") == 0) {
635 switch (match_cfg_line_group(arg, line, user)) { 657 if (ci == NULL || ci->user == NULL) {
658 result = 0;
659 continue;
660 }
661 switch (match_cfg_line_group(arg, line, ci->user)) {
636 case -1: 662 case -1:
637 return -1; 663 return -1;
638 case 0: 664 case 0:
639 result = 0; 665 result = 0;
640 } 666 }
641 } else if (strcasecmp(attrib, "host") == 0) { 667 } else if (strcasecmp(attrib, "host") == 0) {
642 if (!host) { 668 if (ci == NULL || ci->host == NULL) {
643 result = 0; 669 result = 0;
644 continue; 670 continue;
645 } 671 }
646 if (match_hostname(host, arg, len) != 1) 672 if (match_hostname(ci->host, arg, len) != 1)
647 result = 0; 673 result = 0;
648 else 674 else
649 debug("connection from %.100s matched 'Host " 675 debug("connection from %.100s matched 'Host "
650 "%.100s' at line %d", host, arg, line); 676 "%.100s' at line %d", ci->host, arg, line);
651 } else if (strcasecmp(attrib, "address") == 0) { 677 } else if (strcasecmp(attrib, "address") == 0) {
652 switch (addr_match_list(address, arg)) { 678 if (ci == NULL || ci->address == NULL) {
679 result = 0;
680 continue;
681 }
682 switch (addr_match_list(ci->address, arg)) {
653 case 1: 683 case 1:
654 debug("connection from %.100s matched 'Address " 684 debug("connection from %.100s matched 'Address "
655 "%.100s' at line %d", address, arg, line); 685 "%.100s' at line %d", ci->address, arg, line);
656 break; 686 break;
657 case 0: 687 case 0:
658 case -1: 688 case -1:
@@ -661,12 +691,47 @@ match_cfg_line(char **condition, int line, const char *user, const char *host,
661 case -2: 691 case -2:
662 return -1; 692 return -1;
663 } 693 }
694 } else if (strcasecmp(attrib, "localaddress") == 0){
695 if (ci == NULL || ci->laddress == NULL) {
696 result = 0;
697 continue;
698 }
699 switch (addr_match_list(ci->laddress, arg)) {
700 case 1:
701 debug("connection from %.100s matched "
702 "'LocalAddress %.100s' at line %d",
703 ci->laddress, arg, line);
704 break;
705 case 0:
706 case -1:
707 result = 0;
708 break;
709 case -2:
710 return -1;
711 }
712 } else if (strcasecmp(attrib, "localport") == 0) {
713 if ((port = a2port(arg)) == -1) {
714 error("Invalid LocalPort '%s' on Match line",
715 arg);
716 return -1;
717 }
718 if (ci == NULL || ci->lport == 0) {
719 result = 0;
720 continue;
721 }
722 /* TODO support port lists */
723 if (port == ci->lport)
724 debug("connection from %.100s matched "
725 "'LocalPort %d' at line %d",
726 ci->laddress, port, line);
727 else
728 result = 0;
664 } else { 729 } else {
665 error("Unsupported Match attribute %s", attrib); 730 error("Unsupported Match attribute %s", attrib);
666 return -1; 731 return -1;
667 } 732 }
668 } 733 }
669 if (user != NULL) 734 if (ci != NULL)
670 debug3("match %sfound", result ? "" : "not "); 735 debug3("match %sfound", result ? "" : "not ");
671 *condition = cp; 736 *condition = cp;
672 return result; 737 return result;
@@ -713,8 +778,8 @@ static const struct multistate multistate_privsep[] = {
713 778
714int 779int
715process_server_config_line(ServerOptions *options, char *line, 780process_server_config_line(ServerOptions *options, char *line,
716 const char *filename, int linenum, int *activep, const char *user, 781 const char *filename, int linenum, int *activep,
717 const char *host, const char *address) 782 struct connection_info *connectinfo)
718{ 783{
719 char *cp, **charptr, *arg, *p; 784 char *cp, **charptr, *arg, *p;
720 int cmdline = 0, *intptr, value, value2, n; 785 int cmdline = 0, *intptr, value, value2, n;
@@ -745,7 +810,7 @@ process_server_config_line(ServerOptions *options, char *line,
745 if (*activep && opcode != sMatch) 810 if (*activep && opcode != sMatch)
746 debug3("%s:%d setting %s %s", filename, linenum, arg, cp); 811 debug3("%s:%d setting %s %s", filename, linenum, arg, cp);
747 if (*activep == 0 && !(flags & SSHCFG_MATCH)) { 812 if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
748 if (user == NULL) { 813 if (connectinfo == NULL) {
749 fatal("%s line %d: Directive '%s' is not allowed " 814 fatal("%s line %d: Directive '%s' is not allowed "
750 "within a Match block", filename, linenum, arg); 815 "within a Match block", filename, linenum, arg);
751 } else { /* this is a directive we have already processed */ 816 } else { /* this is a directive we have already processed */
@@ -1316,7 +1381,7 @@ process_server_config_line(ServerOptions *options, char *line,
1316 if (cmdline) 1381 if (cmdline)
1317 fatal("Match directive not supported as a command-line " 1382 fatal("Match directive not supported as a command-line "
1318 "option"); 1383 "option");
1319 value = match_cfg_line(&cp, linenum, user, host, address); 1384 value = match_cfg_line(&cp, linenum, connectinfo);
1320 if (value < 0) 1385 if (value < 0)
1321 fatal("%s line %d: Bad Match condition", filename, 1386 fatal("%s line %d: Bad Match condition", filename,
1322 linenum); 1387 linenum);
@@ -1478,16 +1543,58 @@ load_server_config(const char *filename, Buffer *conf)
1478} 1543}
1479 1544
1480void 1545void
1481parse_server_match_config(ServerOptions *options, const char *user, 1546parse_server_match_config(ServerOptions *options,
1482 const char *host, const char *address) 1547 struct connection_info *connectinfo)
1483{ 1548{
1484 ServerOptions mo; 1549 ServerOptions mo;
1485 1550
1486 initialize_server_options(&mo); 1551 initialize_server_options(&mo);
1487 parse_server_config(&mo, "reprocess config", &cfg, user, host, address); 1552 parse_server_config(&mo, "reprocess config", &cfg, connectinfo);
1488 copy_set_server_options(options, &mo, 0); 1553 copy_set_server_options(options, &mo, 0);
1489} 1554}
1490 1555
1556int parse_server_match_testspec(struct connection_info *ci, char *spec)
1557{
1558 char *p;
1559
1560 while ((p = strsep(&spec, ",")) && *p != '\0') {
1561 if (strncmp(p, "addr=", 5) == 0) {
1562 ci->address = xstrdup(p + 5);
1563 } else if (strncmp(p, "host=", 5) == 0) {
1564 ci->host = xstrdup(p + 5);
1565 } else if (strncmp(p, "user=", 5) == 0) {
1566 ci->user = xstrdup(p + 5);
1567 } else if (strncmp(p, "laddr=", 6) == 0) {
1568 ci->laddress = xstrdup(p + 6);
1569 } else if (strncmp(p, "lport=", 6) == 0) {
1570 ci->lport = a2port(p + 6);
1571 if (ci->lport == -1) {
1572 fprintf(stderr, "Invalid port '%s' in test mode"
1573 " specification %s\n", p+6, p);
1574 return -1;
1575 }
1576 } else {
1577 fprintf(stderr, "Invalid test mode specification %s\n",
1578 p);
1579 return -1;
1580 }
1581 }
1582 return 0;
1583}
1584
1585/*
1586 * returns 1 for a complete spec, 0 for partial spec and -1 for an
1587 * empty spec.
1588 */
1589int server_match_spec_complete(struct connection_info *ci)
1590{
1591 if (ci->user && ci->host && ci->address)
1592 return 1; /* complete */
1593 if (!ci->user && !ci->host && !ci->address)
1594 return -1; /* empty */
1595 return 0; /* partial */
1596}
1597
1491/* Helper macros */ 1598/* Helper macros */
1492#define M_CP_INTOPT(n) do {\ 1599#define M_CP_INTOPT(n) do {\
1493 if (src->n != -1) \ 1600 if (src->n != -1) \
@@ -1561,7 +1668,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
1561 1668
1562void 1669void
1563parse_server_config(ServerOptions *options, const char *filename, Buffer *conf, 1670parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
1564 const char *user, const char *host, const char *address) 1671 struct connection_info *connectinfo)
1565{ 1672{
1566 int active, linenum, bad_options = 0; 1673 int active, linenum, bad_options = 0;
1567 char *cp, *obuf, *cbuf; 1674 char *cp, *obuf, *cbuf;
@@ -1569,11 +1676,11 @@ parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
1569 debug2("%s: config %s len %d", __func__, filename, buffer_len(conf)); 1676 debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));
1570 1677
1571 obuf = cbuf = xstrdup(buffer_ptr(conf)); 1678 obuf = cbuf = xstrdup(buffer_ptr(conf));
1572 active = user ? 0 : 1; 1679 active = connectinfo ? 0 : 1;
1573 linenum = 1; 1680 linenum = 1;
1574 while ((cp = strsep(&cbuf, "\n")) != NULL) { 1681 while ((cp = strsep(&cbuf, "\n")) != NULL) {
1575 if (process_server_config_line(options, cp, filename, 1682 if (process_server_config_line(options, cp, filename,
1576 linenum++, &active, user, host, address) != 0) 1683 linenum++, &active, connectinfo) != 0)
1577 bad_options++; 1684 bad_options++;
1578 } 1685 }
1579 xfree(obuf); 1686 xfree(obuf);