diff options
author | Darren Tucker <dtucker@zip.com.au> | 2012-05-19 19:37:01 +1000 |
---|---|---|
committer | Darren Tucker <dtucker@zip.com.au> | 2012-05-19 19:37:01 +1000 |
commit | fbcf827559b38f7992e1bd0bcdc4b4ccdf63bc74 (patch) | |
tree | f13d5eac3813d70d50c50196716981b79c606063 /servconf.c | |
parent | 593538911a4d27f11f8d56e32abe141223c25916 (diff) |
- (dtucker) OpenBSD CVS Sync
- dtucker@cvs.openbsd.org 2012/05/13 01:42:32
[servconf.h servconf.c sshd.8 sshd.c auth.c sshd_config.5]
Add "Match LocalAddress" and "Match LocalPort" to sshd and adjust tests
to match. Feedback and ok djm@ markus@.
Diffstat (limited to 'servconf.c')
-rw-r--r-- | servconf.c | 163 |
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 | ||
49 | static void add_listen_addr(ServerOptions *, char *, int); | 52 | static void add_listen_addr(ServerOptions *, char *, int); |
50 | static void add_one_listen_addr(ServerOptions *, char *, int); | 53 | static 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 | ||
545 | struct connection_info * | ||
546 | get_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 | */ | ||
603 | static int | 624 | static int |
604 | match_cfg_line(char **condition, int line, const char *user, const char *host, | 625 | match_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 | ||
714 | int | 779 | int |
715 | process_server_config_line(ServerOptions *options, char *line, | 780 | process_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 | ||
1480 | void | 1545 | void |
1481 | parse_server_match_config(ServerOptions *options, const char *user, | 1546 | parse_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 | ||
1556 | int 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 | */ | ||
1589 | int 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 | ||
1562 | void | 1669 | void |
1563 | parse_server_config(ServerOptions *options, const char *filename, Buffer *conf, | 1670 | parse_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); |