diff options
Diffstat (limited to 'channels.c')
-rw-r--r-- | channels.c | 477 |
1 files changed, 303 insertions, 174 deletions
diff --git a/channels.c b/channels.c index 65d9dbd5f..1b40d7da6 100644 --- a/channels.c +++ b/channels.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: channels.c,v 1.380 2018/04/10 00:10:49 djm Exp $ */ | 1 | /* $OpenBSD: channels.c,v 1.381 2018/06/06 18:22:41 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -82,6 +82,7 @@ | |||
82 | #include "key.h" | 82 | #include "key.h" |
83 | #include "authfd.h" | 83 | #include "authfd.h" |
84 | #include "pathnames.h" | 84 | #include "pathnames.h" |
85 | #include "match.h" | ||
85 | 86 | ||
86 | /* -- agent forwarding */ | 87 | /* -- agent forwarding */ |
87 | #define NUM_SOCKS 10 | 88 | #define NUM_SOCKS 10 |
@@ -97,6 +98,10 @@ | |||
97 | /* Maximum number of fake X11 displays to try. */ | 98 | /* Maximum number of fake X11 displays to try. */ |
98 | #define MAX_DISPLAYS 1000 | 99 | #define MAX_DISPLAYS 1000 |
99 | 100 | ||
101 | /* Per-channel callback for pre/post select() actions */ | ||
102 | typedef void chan_fn(struct ssh *, Channel *c, | ||
103 | fd_set *readset, fd_set *writeset); | ||
104 | |||
100 | /* | 105 | /* |
101 | * Data structure for storing which hosts are permitted for forward requests. | 106 | * Data structure for storing which hosts are permitted for forward requests. |
102 | * The local sides of any remote forwards are stored in this array to prevent | 107 | * The local sides of any remote forwards are stored in this array to prevent |
@@ -106,17 +111,40 @@ | |||
106 | /* XXX: streamlocal wants a path instead of host:port */ | 111 | /* XXX: streamlocal wants a path instead of host:port */ |
107 | /* Overload host_to_connect; we could just make this match Forward */ | 112 | /* Overload host_to_connect; we could just make this match Forward */ |
108 | /* XXX - can we use listen_host instead of listen_path? */ | 113 | /* XXX - can we use listen_host instead of listen_path? */ |
109 | typedef struct { | 114 | struct permission { |
110 | char *host_to_connect; /* Connect to 'host'. */ | 115 | char *host_to_connect; /* Connect to 'host'. */ |
111 | int port_to_connect; /* Connect to 'port'. */ | 116 | int port_to_connect; /* Connect to 'port'. */ |
112 | char *listen_host; /* Remote side should listen address. */ | 117 | char *listen_host; /* Remote side should listen address. */ |
113 | char *listen_path; /* Remote side should listen path. */ | 118 | char *listen_path; /* Remote side should listen path. */ |
114 | int listen_port; /* Remote side should listen port. */ | 119 | int listen_port; /* Remote side should listen port. */ |
115 | Channel *downstream; /* Downstream mux*/ | 120 | Channel *downstream; /* Downstream mux*/ |
116 | } ForwardPermission; | 121 | }; |
117 | 122 | ||
118 | typedef void chan_fn(struct ssh *, Channel *c, | 123 | /* |
119 | fd_set *readset, fd_set *writeset); | 124 | * Stores the forwarding permission state for a single direction (local or |
125 | * remote). | ||
126 | */ | ||
127 | struct permission_set { | ||
128 | /* | ||
129 | * List of all local permitted host/port pairs to allow for the | ||
130 | * user. | ||
131 | */ | ||
132 | u_int num_permitted_user; | ||
133 | struct permission *permitted_user; | ||
134 | |||
135 | /* | ||
136 | * List of all permitted host/port pairs to allow for the admin. | ||
137 | */ | ||
138 | u_int num_permitted_admin; | ||
139 | struct permission *permitted_admin; | ||
140 | |||
141 | /* | ||
142 | * If this is true, all opens/listens are permitted. This is the | ||
143 | * case on the server on which we have to trust the client anyway, | ||
144 | * and the user could do anything after logging in. | ||
145 | */ | ||
146 | int all_permitted; | ||
147 | }; | ||
120 | 148 | ||
121 | /* Master structure for channels state */ | 149 | /* Master structure for channels state */ |
122 | struct ssh_channels { | 150 | struct ssh_channels { |
@@ -149,31 +177,8 @@ struct ssh_channels { | |||
149 | chan_fn **channel_post; | 177 | chan_fn **channel_post; |
150 | 178 | ||
151 | /* -- tcp forwarding */ | 179 | /* -- tcp forwarding */ |
152 | 180 | struct permission_set local_perms; | |
153 | /* List of all permitted host/port pairs to connect by the user. */ | 181 | struct permission_set remote_perms; |
154 | ForwardPermission *permitted_opens; | ||
155 | |||
156 | /* List of all permitted host/port pairs to connect by the admin. */ | ||
157 | ForwardPermission *permitted_adm_opens; | ||
158 | |||
159 | /* | ||
160 | * Number of permitted host/port pairs in the array permitted by | ||
161 | * the user. | ||
162 | */ | ||
163 | u_int num_permitted_opens; | ||
164 | |||
165 | /* | ||
166 | * Number of permitted host/port pair in the array permitted by | ||
167 | * the admin. | ||
168 | */ | ||
169 | u_int num_adm_permitted_opens; | ||
170 | |||
171 | /* | ||
172 | * If this is true, all opens are permitted. This is the case on | ||
173 | * the server on which we have to trust the client anyway, and the | ||
174 | * user could do anything after logging in anyway. | ||
175 | */ | ||
176 | int all_opens_permitted; | ||
177 | 182 | ||
178 | /* -- X11 forwarding */ | 183 | /* -- X11 forwarding */ |
179 | 184 | ||
@@ -448,50 +453,95 @@ channel_close_fds(struct ssh *ssh, Channel *c) | |||
448 | } | 453 | } |
449 | 454 | ||
450 | static void | 455 | static void |
451 | fwd_perm_clear(ForwardPermission *fp) | 456 | fwd_perm_clear(struct permission *perm) |
452 | { | 457 | { |
453 | free(fp->host_to_connect); | 458 | free(perm->host_to_connect); |
454 | free(fp->listen_host); | 459 | free(perm->listen_host); |
455 | free(fp->listen_path); | 460 | free(perm->listen_path); |
456 | bzero(fp, sizeof(*fp)); | 461 | bzero(perm, sizeof(*perm)); |
457 | } | 462 | } |
458 | 463 | ||
459 | enum { FWDPERM_USER, FWDPERM_ADMIN }; | 464 | /* Returns an printable name for the specified forwarding permission list */ |
465 | static const char * | ||
466 | fwd_ident(int who, int where) | ||
467 | { | ||
468 | if (who == FORWARD_ADM) { | ||
469 | if (where == FORWARD_LOCAL) | ||
470 | return "admin local"; | ||
471 | else if (where == FORWARD_REMOTE) | ||
472 | return "admin remote"; | ||
473 | } else if (who == FORWARD_USER) { | ||
474 | if (where == FORWARD_LOCAL) | ||
475 | return "user local"; | ||
476 | else if (where == FORWARD_REMOTE) | ||
477 | return "user remote"; | ||
478 | } | ||
479 | fatal("Unknown forward permission list %d/%d", who, where); | ||
480 | } | ||
460 | 481 | ||
461 | static int | 482 | /* Returns the forwarding permission list for the specified direction */ |
462 | fwd_perm_list_add(struct ssh *ssh, int which, | 483 | static struct permission_set * |
463 | const char *host_to_connect, int port_to_connect, | 484 | permission_set_get(struct ssh *ssh, int where) |
464 | const char *listen_host, const char *listen_path, int listen_port, | ||
465 | Channel *downstream) | ||
466 | { | 485 | { |
467 | ForwardPermission **fpl; | 486 | struct ssh_channels *sc = ssh->chanctxt; |
468 | u_int n, *nfpl; | ||
469 | 487 | ||
470 | switch (which) { | 488 | switch (where) { |
471 | case FWDPERM_USER: | 489 | case FORWARD_LOCAL: |
472 | fpl = &ssh->chanctxt->permitted_opens; | 490 | return &sc->local_perms; |
473 | nfpl = &ssh->chanctxt->num_permitted_opens; | ||
474 | break; | 491 | break; |
475 | case FWDPERM_ADMIN: | 492 | case FORWARD_REMOTE: |
476 | fpl = &ssh->chanctxt->permitted_adm_opens; | 493 | return &sc->remote_perms; |
477 | nfpl = &ssh->chanctxt->num_adm_permitted_opens; | ||
478 | break; | 494 | break; |
479 | default: | 495 | default: |
480 | fatal("%s: invalid list %d", __func__, which); | 496 | fatal("%s: invalid forwarding direction %d", __func__, where); |
481 | } | 497 | } |
498 | } | ||
482 | 499 | ||
483 | if (*nfpl >= INT_MAX) | 500 | /* Reutrns pointers to the specified forwarding list and its element count */ |
484 | fatal("%s: overflow", __func__); | 501 | static void |
502 | permission_set_get_array(struct ssh *ssh, int who, int where, | ||
503 | struct permission ***permpp, u_int **npermpp) | ||
504 | { | ||
505 | struct permission_set *pset = permission_set_get(ssh, where); | ||
485 | 506 | ||
486 | *fpl = xrecallocarray(*fpl, *nfpl, *nfpl + 1, sizeof(**fpl)); | 507 | switch (who) { |
487 | n = (*nfpl)++; | 508 | case FORWARD_USER: |
509 | *permpp = &pset->permitted_user; | ||
510 | *npermpp = &pset->num_permitted_user; | ||
511 | break; | ||
512 | case FORWARD_ADM: | ||
513 | *permpp = &pset->permitted_admin; | ||
514 | *npermpp = &pset->num_permitted_admin; | ||
515 | break; | ||
516 | default: | ||
517 | fatal("%s: invalid forwarding client %d", __func__, who); | ||
518 | } | ||
519 | } | ||
520 | |||
521 | /* Adds an entry to the spcified forwarding list */ | ||
522 | static int | ||
523 | permission_set_add(struct ssh *ssh, int who, int where, | ||
524 | const char *host_to_connect, int port_to_connect, | ||
525 | const char *listen_host, const char *listen_path, int listen_port, | ||
526 | Channel *downstream) | ||
527 | { | ||
528 | struct permission **permp; | ||
529 | u_int n, *npermp; | ||
530 | |||
531 | permission_set_get_array(ssh, who, where, &permp, &npermp); | ||
532 | |||
533 | if (*npermp >= INT_MAX) | ||
534 | fatal("%s: %s overflow", __func__, fwd_ident(who, where)); | ||
535 | |||
536 | *permp = xrecallocarray(*permp, *npermp, *npermp + 1, sizeof(**permp)); | ||
537 | n = (*npermp)++; | ||
488 | #define MAYBE_DUP(s) ((s == NULL) ? NULL : xstrdup(s)) | 538 | #define MAYBE_DUP(s) ((s == NULL) ? NULL : xstrdup(s)) |
489 | (*fpl)[n].host_to_connect = MAYBE_DUP(host_to_connect); | 539 | (*permp)[n].host_to_connect = MAYBE_DUP(host_to_connect); |
490 | (*fpl)[n].port_to_connect = port_to_connect; | 540 | (*permp)[n].port_to_connect = port_to_connect; |
491 | (*fpl)[n].listen_host = MAYBE_DUP(listen_host); | 541 | (*permp)[n].listen_host = MAYBE_DUP(listen_host); |
492 | (*fpl)[n].listen_path = MAYBE_DUP(listen_path); | 542 | (*permp)[n].listen_path = MAYBE_DUP(listen_path); |
493 | (*fpl)[n].listen_port = listen_port; | 543 | (*permp)[n].listen_port = listen_port; |
494 | (*fpl)[n].downstream = downstream; | 544 | (*permp)[n].downstream = downstream; |
495 | #undef MAYBE_DUP | 545 | #undef MAYBE_DUP |
496 | return (int)n; | 546 | return (int)n; |
497 | } | 547 | } |
@@ -500,30 +550,31 @@ static void | |||
500 | mux_remove_remote_forwardings(struct ssh *ssh, Channel *c) | 550 | mux_remove_remote_forwardings(struct ssh *ssh, Channel *c) |
501 | { | 551 | { |
502 | struct ssh_channels *sc = ssh->chanctxt; | 552 | struct ssh_channels *sc = ssh->chanctxt; |
503 | ForwardPermission *fp; | 553 | struct permission_set *pset = &sc->local_perms; |
554 | struct permission *perm; | ||
504 | int r; | 555 | int r; |
505 | u_int i; | 556 | u_int i; |
506 | 557 | ||
507 | for (i = 0; i < sc->num_permitted_opens; i++) { | 558 | for (i = 0; i < pset->num_permitted_user; i++) { |
508 | fp = &sc->permitted_opens[i]; | 559 | perm = &pset->permitted_user[i]; |
509 | if (fp->downstream != c) | 560 | if (perm->downstream != c) |
510 | continue; | 561 | continue; |
511 | 562 | ||
512 | /* cancel on the server, since mux client is gone */ | 563 | /* cancel on the server, since mux client is gone */ |
513 | debug("channel %d: cleanup remote forward for %s:%u", | 564 | debug("channel %d: cleanup remote forward for %s:%u", |
514 | c->self, fp->listen_host, fp->listen_port); | 565 | c->self, perm->listen_host, perm->listen_port); |
515 | if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 || | 566 | if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 || |
516 | (r = sshpkt_put_cstring(ssh, | 567 | (r = sshpkt_put_cstring(ssh, |
517 | "cancel-tcpip-forward")) != 0 || | 568 | "cancel-tcpip-forward")) != 0 || |
518 | (r = sshpkt_put_u8(ssh, 0)) != 0 || | 569 | (r = sshpkt_put_u8(ssh, 0)) != 0 || |
519 | (r = sshpkt_put_cstring(ssh, | 570 | (r = sshpkt_put_cstring(ssh, |
520 | channel_rfwd_bind_host(fp->listen_host))) != 0 || | 571 | channel_rfwd_bind_host(perm->listen_host))) != 0 || |
521 | (r = sshpkt_put_u32(ssh, fp->listen_port)) != 0 || | 572 | (r = sshpkt_put_u32(ssh, perm->listen_port)) != 0 || |
522 | (r = sshpkt_send(ssh)) != 0) { | 573 | (r = sshpkt_send(ssh)) != 0) { |
523 | fatal("%s: channel %i: %s", __func__, | 574 | fatal("%s: channel %i: %s", __func__, |
524 | c->self, ssh_err(r)); | 575 | c->self, ssh_err(r)); |
525 | } | 576 | } |
526 | fwd_perm_clear(fp); /* unregister */ | 577 | fwd_perm_clear(perm); /* unregister */ |
527 | } | 578 | } |
528 | } | 579 | } |
529 | 580 | ||
@@ -2729,7 +2780,7 @@ channel_proxy_downstream(struct ssh *ssh, Channel *downstream) | |||
2729 | goto out; | 2780 | goto out; |
2730 | } | 2781 | } |
2731 | /* Record that connection to this host/port is permitted. */ | 2782 | /* Record that connection to this host/port is permitted. */ |
2732 | fwd_perm_list_add(ssh, FWDPERM_USER, "<mux>", -1, | 2783 | permission_set_add(ssh, FORWARD_USER, FORWARD_LOCAL, "<mux>", -1, |
2733 | listen_host, NULL, (int)listen_port, downstream); | 2784 | listen_host, NULL, (int)listen_port, downstream); |
2734 | listen_host = NULL; | 2785 | listen_host = NULL; |
2735 | break; | 2786 | break; |
@@ -3637,11 +3688,78 @@ channel_setup_local_fwd_listener(struct ssh *ssh, | |||
3637 | } | 3688 | } |
3638 | } | 3689 | } |
3639 | 3690 | ||
3691 | /* Matches a remote forwarding permission against a requested forwarding */ | ||
3692 | static int | ||
3693 | remote_open_match(struct permission *allowed_open, struct Forward *fwd) | ||
3694 | { | ||
3695 | int ret; | ||
3696 | char *lhost; | ||
3697 | |||
3698 | /* XXX add ACLs for streamlocal */ | ||
3699 | if (fwd->listen_path != NULL) | ||
3700 | return 1; | ||
3701 | |||
3702 | if (fwd->listen_host == NULL || allowed_open->listen_host == NULL) | ||
3703 | return 0; | ||
3704 | |||
3705 | if (allowed_open->listen_port != FWD_PERMIT_ANY_PORT && | ||
3706 | allowed_open->listen_port != fwd->listen_port) | ||
3707 | return 0; | ||
3708 | |||
3709 | /* Match hostnames case-insensitively */ | ||
3710 | lhost = xstrdup(fwd->listen_host); | ||
3711 | lowercase(lhost); | ||
3712 | ret = match_pattern(lhost, allowed_open->listen_host); | ||
3713 | free(lhost); | ||
3714 | |||
3715 | return ret; | ||
3716 | } | ||
3717 | |||
3718 | /* Checks whether a requested remote forwarding is permitted */ | ||
3719 | static int | ||
3720 | check_rfwd_permission(struct ssh *ssh, struct Forward *fwd) | ||
3721 | { | ||
3722 | struct ssh_channels *sc = ssh->chanctxt; | ||
3723 | struct permission_set *pset = &sc->remote_perms; | ||
3724 | u_int i, permit, permit_adm = 1; | ||
3725 | struct permission *perm; | ||
3726 | |||
3727 | /* XXX apply GatewayPorts override before checking? */ | ||
3728 | |||
3729 | permit = pset->all_permitted; | ||
3730 | if (!permit) { | ||
3731 | for (i = 0; i < pset->num_permitted_user; i++) { | ||
3732 | perm = &pset->permitted_user[i]; | ||
3733 | if (remote_open_match(perm, fwd)) { | ||
3734 | permit = 1; | ||
3735 | break; | ||
3736 | } | ||
3737 | } | ||
3738 | } | ||
3739 | |||
3740 | if (pset->num_permitted_admin > 0) { | ||
3741 | permit_adm = 0; | ||
3742 | for (i = 0; i < pset->num_permitted_admin; i++) { | ||
3743 | perm = &pset->permitted_admin[i]; | ||
3744 | if (remote_open_match(perm, fwd)) { | ||
3745 | permit_adm = 1; | ||
3746 | break; | ||
3747 | } | ||
3748 | } | ||
3749 | } | ||
3750 | |||
3751 | return permit && permit_adm; | ||
3752 | } | ||
3753 | |||
3640 | /* protocol v2 remote port fwd, used by sshd */ | 3754 | /* protocol v2 remote port fwd, used by sshd */ |
3641 | int | 3755 | int |
3642 | channel_setup_remote_fwd_listener(struct ssh *ssh, struct Forward *fwd, | 3756 | channel_setup_remote_fwd_listener(struct ssh *ssh, struct Forward *fwd, |
3643 | int *allocated_listen_port, struct ForwardOptions *fwd_opts) | 3757 | int *allocated_listen_port, struct ForwardOptions *fwd_opts) |
3644 | { | 3758 | { |
3759 | if (!check_rfwd_permission(ssh, fwd)) { | ||
3760 | packet_send_debug("port forwarding refused"); | ||
3761 | return 0; | ||
3762 | } | ||
3645 | if (fwd->listen_path != NULL) { | 3763 | if (fwd->listen_path != NULL) { |
3646 | return channel_setup_fwd_listener_streamlocal(ssh, | 3764 | return channel_setup_fwd_listener_streamlocal(ssh, |
3647 | SSH_CHANNEL_RUNIX_LISTENER, fwd, fwd_opts); | 3765 | SSH_CHANNEL_RUNIX_LISTENER, fwd, fwd_opts); |
@@ -3671,7 +3789,7 @@ channel_rfwd_bind_host(const char *listen_host) | |||
3671 | * Initiate forwarding of connections to port "port" on remote host through | 3789 | * Initiate forwarding of connections to port "port" on remote host through |
3672 | * the secure channel to host:port from local side. | 3790 | * the secure channel to host:port from local side. |
3673 | * Returns handle (index) for updating the dynamic listen port with | 3791 | * Returns handle (index) for updating the dynamic listen port with |
3674 | * channel_update_permitted_opens(). | 3792 | * channel_update_permission(). |
3675 | */ | 3793 | */ |
3676 | int | 3794 | int |
3677 | channel_request_remote_forwarding(struct ssh *ssh, struct Forward *fwd) | 3795 | channel_request_remote_forwarding(struct ssh *ssh, struct Forward *fwd) |
@@ -3724,7 +3842,7 @@ channel_request_remote_forwarding(struct ssh *ssh, struct Forward *fwd) | |||
3724 | listen_host = xstrdup(fwd->listen_host); | 3842 | listen_host = xstrdup(fwd->listen_host); |
3725 | listen_port = fwd->listen_port; | 3843 | listen_port = fwd->listen_port; |
3726 | } | 3844 | } |
3727 | idx = fwd_perm_list_add(ssh, FWDPERM_USER, | 3845 | idx = permission_set_add(ssh, FORWARD_USER, FORWARD_LOCAL, |
3728 | host_to_connect, port_to_connect, | 3846 | host_to_connect, port_to_connect, |
3729 | listen_host, listen_path, listen_port, NULL); | 3847 | listen_host, listen_path, listen_port, NULL); |
3730 | } | 3848 | } |
@@ -3732,7 +3850,7 @@ channel_request_remote_forwarding(struct ssh *ssh, struct Forward *fwd) | |||
3732 | } | 3850 | } |
3733 | 3851 | ||
3734 | static int | 3852 | static int |
3735 | open_match(ForwardPermission *allowed_open, const char *requestedhost, | 3853 | open_match(struct permission *allowed_open, const char *requestedhost, |
3736 | int requestedport) | 3854 | int requestedport) |
3737 | { | 3855 | { |
3738 | if (allowed_open->host_to_connect == NULL) | 3856 | if (allowed_open->host_to_connect == NULL) |
@@ -3753,7 +3871,7 @@ open_match(ForwardPermission *allowed_open, const char *requestedhost, | |||
3753 | * and what we've sent to the remote server (channel_rfwd_bind_host) | 3871 | * and what we've sent to the remote server (channel_rfwd_bind_host) |
3754 | */ | 3872 | */ |
3755 | static int | 3873 | static int |
3756 | open_listen_match_tcpip(ForwardPermission *allowed_open, | 3874 | open_listen_match_tcpip(struct permission *allowed_open, |
3757 | const char *requestedhost, u_short requestedport, int translate) | 3875 | const char *requestedhost, u_short requestedport, int translate) |
3758 | { | 3876 | { |
3759 | const char *allowed_host; | 3877 | const char *allowed_host; |
@@ -3775,7 +3893,7 @@ open_listen_match_tcpip(ForwardPermission *allowed_open, | |||
3775 | } | 3893 | } |
3776 | 3894 | ||
3777 | static int | 3895 | static int |
3778 | open_listen_match_streamlocal(ForwardPermission *allowed_open, | 3896 | open_listen_match_streamlocal(struct permission *allowed_open, |
3779 | const char *requestedpath) | 3897 | const char *requestedpath) |
3780 | { | 3898 | { |
3781 | if (allowed_open->host_to_connect == NULL) | 3899 | if (allowed_open->host_to_connect == NULL) |
@@ -3797,17 +3915,18 @@ channel_request_rforward_cancel_tcpip(struct ssh *ssh, | |||
3797 | const char *host, u_short port) | 3915 | const char *host, u_short port) |
3798 | { | 3916 | { |
3799 | struct ssh_channels *sc = ssh->chanctxt; | 3917 | struct ssh_channels *sc = ssh->chanctxt; |
3918 | struct permission_set *pset = &sc->local_perms; | ||
3800 | int r; | 3919 | int r; |
3801 | u_int i; | 3920 | u_int i; |
3802 | ForwardPermission *fp; | 3921 | struct permission *perm; |
3803 | 3922 | ||
3804 | for (i = 0; i < sc->num_permitted_opens; i++) { | 3923 | for (i = 0; i < pset->num_permitted_user; i++) { |
3805 | fp = &sc->permitted_opens[i]; | 3924 | perm = &pset->permitted_user[i]; |
3806 | if (open_listen_match_tcpip(fp, host, port, 0)) | 3925 | if (open_listen_match_tcpip(perm, host, port, 0)) |
3807 | break; | 3926 | break; |
3808 | fp = NULL; | 3927 | perm = NULL; |
3809 | } | 3928 | } |
3810 | if (fp == NULL) { | 3929 | if (perm == NULL) { |
3811 | debug("%s: requested forward not found", __func__); | 3930 | debug("%s: requested forward not found", __func__); |
3812 | return -1; | 3931 | return -1; |
3813 | } | 3932 | } |
@@ -3819,7 +3938,7 @@ channel_request_rforward_cancel_tcpip(struct ssh *ssh, | |||
3819 | (r = sshpkt_send(ssh)) != 0) | 3938 | (r = sshpkt_send(ssh)) != 0) |
3820 | fatal("%s: send cancel: %s", __func__, ssh_err(r)); | 3939 | fatal("%s: send cancel: %s", __func__, ssh_err(r)); |
3821 | 3940 | ||
3822 | fwd_perm_clear(fp); /* unregister */ | 3941 | fwd_perm_clear(perm); /* unregister */ |
3823 | 3942 | ||
3824 | return 0; | 3943 | return 0; |
3825 | } | 3944 | } |
@@ -3832,17 +3951,18 @@ static int | |||
3832 | channel_request_rforward_cancel_streamlocal(struct ssh *ssh, const char *path) | 3951 | channel_request_rforward_cancel_streamlocal(struct ssh *ssh, const char *path) |
3833 | { | 3952 | { |
3834 | struct ssh_channels *sc = ssh->chanctxt; | 3953 | struct ssh_channels *sc = ssh->chanctxt; |
3954 | struct permission_set *pset = &sc->local_perms; | ||
3835 | int r; | 3955 | int r; |
3836 | u_int i; | 3956 | u_int i; |
3837 | ForwardPermission *fp; | 3957 | struct permission *perm; |
3838 | 3958 | ||
3839 | for (i = 0; i < sc->num_permitted_opens; i++) { | 3959 | for (i = 0; i < pset->num_permitted_user; i++) { |
3840 | fp = &sc->permitted_opens[i]; | 3960 | perm = &pset->permitted_user[i]; |
3841 | if (open_listen_match_streamlocal(fp, path)) | 3961 | if (open_listen_match_streamlocal(perm, path)) |
3842 | break; | 3962 | break; |
3843 | fp = NULL; | 3963 | perm = NULL; |
3844 | } | 3964 | } |
3845 | if (fp == NULL) { | 3965 | if (perm == NULL) { |
3846 | debug("%s: requested forward not found", __func__); | 3966 | debug("%s: requested forward not found", __func__); |
3847 | return -1; | 3967 | return -1; |
3848 | } | 3968 | } |
@@ -3854,7 +3974,7 @@ channel_request_rforward_cancel_streamlocal(struct ssh *ssh, const char *path) | |||
3854 | (r = sshpkt_send(ssh)) != 0) | 3974 | (r = sshpkt_send(ssh)) != 0) |
3855 | fatal("%s: send cancel: %s", __func__, ssh_err(r)); | 3975 | fatal("%s: send cancel: %s", __func__, ssh_err(r)); |
3856 | 3976 | ||
3857 | fwd_perm_clear(fp); /* unregister */ | 3977 | fwd_perm_clear(perm); /* unregister */ |
3858 | 3978 | ||
3859 | return 0; | 3979 | return 0; |
3860 | } | 3980 | } |
@@ -3876,25 +3996,64 @@ channel_request_rforward_cancel(struct ssh *ssh, struct Forward *fwd) | |||
3876 | } | 3996 | } |
3877 | 3997 | ||
3878 | /* | 3998 | /* |
3879 | * Permits opening to any host/port if permitted_opens[] is empty. This is | 3999 | * Permits opening to any host/port if permitted_user[] is empty. This is |
3880 | * usually called by the server, because the user could connect to any port | 4000 | * usually called by the server, because the user could connect to any port |
3881 | * anyway, and the server has no way to know but to trust the client anyway. | 4001 | * anyway, and the server has no way to know but to trust the client anyway. |
3882 | */ | 4002 | */ |
3883 | void | 4003 | void |
3884 | channel_permit_all_opens(struct ssh *ssh) | 4004 | channel_permit_all(struct ssh *ssh, int where) |
3885 | { | 4005 | { |
3886 | if (ssh->chanctxt->num_permitted_opens == 0) | 4006 | struct permission_set *pset = permission_set_get(ssh, where); |
3887 | ssh->chanctxt->all_opens_permitted = 1; | 4007 | |
4008 | if (pset->num_permitted_user == 0) | ||
4009 | pset->all_permitted = 1; | ||
3888 | } | 4010 | } |
3889 | 4011 | ||
4012 | /* | ||
4013 | * Permit the specified host/port for forwarding. | ||
4014 | */ | ||
3890 | void | 4015 | void |
3891 | channel_add_permitted_opens(struct ssh *ssh, char *host, int port) | 4016 | channel_add_permission(struct ssh *ssh, int who, int where, |
4017 | char *host, int port) | ||
3892 | { | 4018 | { |
3893 | struct ssh_channels *sc = ssh->chanctxt; | 4019 | int local = where == FORWARD_LOCAL; |
4020 | struct permission_set *pset = permission_set_get(ssh, where); | ||
3894 | 4021 | ||
3895 | debug("allow port forwarding to host %s port %d", host, port); | 4022 | debug("allow %s forwarding to host %s port %d", |
3896 | fwd_perm_list_add(ssh, FWDPERM_USER, host, port, NULL, NULL, 0, NULL); | 4023 | fwd_ident(who, where), host, port); |
3897 | sc->all_opens_permitted = 0; | 4024 | /* |
4025 | * Remote forwards set listen_host/port, local forwards set | ||
4026 | * host/port_to_connect. | ||
4027 | */ | ||
4028 | permission_set_add(ssh, who, where, | ||
4029 | local ? host : 0, local ? port : 0, | ||
4030 | local ? NULL : host, NULL, local ? 0 : port, NULL); | ||
4031 | pset->all_permitted = 0; | ||
4032 | } | ||
4033 | |||
4034 | /* | ||
4035 | * Administratively disable forwarding. | ||
4036 | */ | ||
4037 | void | ||
4038 | channel_disable_admin(struct ssh *ssh, int where) | ||
4039 | { | ||
4040 | channel_clear_permission(ssh, FORWARD_ADM, where); | ||
4041 | permission_set_add(ssh, FORWARD_ADM, where, | ||
4042 | NULL, 0, NULL, NULL, 0, NULL); | ||
4043 | } | ||
4044 | |||
4045 | /* | ||
4046 | * Clear a list of permitted opens. | ||
4047 | */ | ||
4048 | void | ||
4049 | channel_clear_permission(struct ssh *ssh, int who, int where) | ||
4050 | { | ||
4051 | struct permission **permp; | ||
4052 | u_int *npermp; | ||
4053 | |||
4054 | permission_set_get_array(ssh, who, where, &permp, &npermp); | ||
4055 | *permp = xrecallocarray(*permp, *npermp, 0, sizeof(**permp)); | ||
4056 | *npermp = 0; | ||
3898 | } | 4057 | } |
3899 | 4058 | ||
3900 | /* | 4059 | /* |
@@ -3903,63 +4062,28 @@ channel_add_permitted_opens(struct ssh *ssh, char *host, int port) | |||
3903 | * passed then they entry will be invalidated. | 4062 | * passed then they entry will be invalidated. |
3904 | */ | 4063 | */ |
3905 | void | 4064 | void |
3906 | channel_update_permitted_opens(struct ssh *ssh, int idx, int newport) | 4065 | channel_update_permission(struct ssh *ssh, int idx, int newport) |
3907 | { | 4066 | { |
3908 | struct ssh_channels *sc = ssh->chanctxt; | 4067 | struct permission_set *pset = &ssh->chanctxt->local_perms; |
3909 | 4068 | ||
3910 | if (idx < 0 || (u_int)idx >= sc->num_permitted_opens) { | 4069 | if (idx < 0 || (u_int)idx >= pset->num_permitted_user) { |
3911 | debug("%s: index out of range: %d num_permitted_opens %d", | 4070 | debug("%s: index out of range: %d num_permitted_user %d", |
3912 | __func__, idx, sc->num_permitted_opens); | 4071 | __func__, idx, pset->num_permitted_user); |
3913 | return; | 4072 | return; |
3914 | } | 4073 | } |
3915 | debug("%s allowed port %d for forwarding to host %s port %d", | 4074 | debug("%s allowed port %d for forwarding to host %s port %d", |
3916 | newport > 0 ? "Updating" : "Removing", | 4075 | newport > 0 ? "Updating" : "Removing", |
3917 | newport, | 4076 | newport, |
3918 | sc->permitted_opens[idx].host_to_connect, | 4077 | pset->permitted_user[idx].host_to_connect, |
3919 | sc->permitted_opens[idx].port_to_connect); | 4078 | pset->permitted_user[idx].port_to_connect); |
3920 | if (newport <= 0) | 4079 | if (newport <= 0) |
3921 | fwd_perm_clear(&sc->permitted_opens[idx]); | 4080 | fwd_perm_clear(&pset->permitted_user[idx]); |
3922 | else { | 4081 | else { |
3923 | sc->permitted_opens[idx].listen_port = | 4082 | pset->permitted_user[idx].listen_port = |
3924 | (datafellows & SSH_BUG_DYNAMIC_RPORT) ? 0 : newport; | 4083 | (datafellows & SSH_BUG_DYNAMIC_RPORT) ? 0 : newport; |
3925 | } | 4084 | } |
3926 | } | 4085 | } |
3927 | 4086 | ||
3928 | int | ||
3929 | channel_add_adm_permitted_opens(struct ssh *ssh, char *host, int port) | ||
3930 | { | ||
3931 | debug("config allows port forwarding to host %s port %d", host, port); | ||
3932 | return fwd_perm_list_add(ssh, FWDPERM_ADMIN, host, port, | ||
3933 | NULL, NULL, 0, NULL); | ||
3934 | } | ||
3935 | |||
3936 | void | ||
3937 | channel_disable_adm_local_opens(struct ssh *ssh) | ||
3938 | { | ||
3939 | channel_clear_adm_permitted_opens(ssh); | ||
3940 | fwd_perm_list_add(ssh, FWDPERM_ADMIN, NULL, 0, NULL, NULL, 0, NULL); | ||
3941 | } | ||
3942 | |||
3943 | void | ||
3944 | channel_clear_permitted_opens(struct ssh *ssh) | ||
3945 | { | ||
3946 | struct ssh_channels *sc = ssh->chanctxt; | ||
3947 | |||
3948 | sc->permitted_opens = xrecallocarray(sc->permitted_opens, | ||
3949 | sc->num_permitted_opens, 0, sizeof(*sc->permitted_opens)); | ||
3950 | sc->num_permitted_opens = 0; | ||
3951 | } | ||
3952 | |||
3953 | void | ||
3954 | channel_clear_adm_permitted_opens(struct ssh *ssh) | ||
3955 | { | ||
3956 | struct ssh_channels *sc = ssh->chanctxt; | ||
3957 | |||
3958 | sc->permitted_adm_opens = xrecallocarray(sc->permitted_adm_opens, | ||
3959 | sc->num_adm_permitted_opens, 0, sizeof(*sc->permitted_adm_opens)); | ||
3960 | sc->num_adm_permitted_opens = 0; | ||
3961 | } | ||
3962 | |||
3963 | /* returns port number, FWD_PERMIT_ANY_PORT or -1 on error */ | 4087 | /* returns port number, FWD_PERMIT_ANY_PORT or -1 on error */ |
3964 | int | 4088 | int |
3965 | permitopen_port(const char *p) | 4089 | permitopen_port(const char *p) |
@@ -4148,19 +4272,21 @@ channel_connect_by_listen_address(struct ssh *ssh, const char *listen_host, | |||
4148 | u_short listen_port, char *ctype, char *rname) | 4272 | u_short listen_port, char *ctype, char *rname) |
4149 | { | 4273 | { |
4150 | struct ssh_channels *sc = ssh->chanctxt; | 4274 | struct ssh_channels *sc = ssh->chanctxt; |
4275 | struct permission_set *pset = &sc->local_perms; | ||
4151 | u_int i; | 4276 | u_int i; |
4152 | ForwardPermission *fp; | 4277 | struct permission *perm; |
4153 | 4278 | ||
4154 | for (i = 0; i < sc->num_permitted_opens; i++) { | 4279 | for (i = 0; i < pset->num_permitted_user; i++) { |
4155 | fp = &sc->permitted_opens[i]; | 4280 | perm = &pset->permitted_user[i]; |
4156 | if (open_listen_match_tcpip(fp, listen_host, listen_port, 1)) { | 4281 | if (open_listen_match_tcpip(perm, |
4157 | if (fp->downstream) | 4282 | listen_host, listen_port, 1)) { |
4158 | return fp->downstream; | 4283 | if (perm->downstream) |
4159 | if (fp->port_to_connect == 0) | 4284 | return perm->downstream; |
4285 | if (perm->port_to_connect == 0) | ||
4160 | return rdynamic_connect_prepare(ssh, | 4286 | return rdynamic_connect_prepare(ssh, |
4161 | ctype, rname); | 4287 | ctype, rname); |
4162 | return connect_to(ssh, | 4288 | return connect_to(ssh, |
4163 | fp->host_to_connect, fp->port_to_connect, | 4289 | perm->host_to_connect, perm->port_to_connect, |
4164 | ctype, rname); | 4290 | ctype, rname); |
4165 | } | 4291 | } |
4166 | } | 4292 | } |
@@ -4174,14 +4300,15 @@ channel_connect_by_listen_path(struct ssh *ssh, const char *path, | |||
4174 | char *ctype, char *rname) | 4300 | char *ctype, char *rname) |
4175 | { | 4301 | { |
4176 | struct ssh_channels *sc = ssh->chanctxt; | 4302 | struct ssh_channels *sc = ssh->chanctxt; |
4303 | struct permission_set *pset = &sc->local_perms; | ||
4177 | u_int i; | 4304 | u_int i; |
4178 | ForwardPermission *fp; | 4305 | struct permission *perm; |
4179 | 4306 | ||
4180 | for (i = 0; i < sc->num_permitted_opens; i++) { | 4307 | for (i = 0; i < pset->num_permitted_user; i++) { |
4181 | fp = &sc->permitted_opens[i]; | 4308 | perm = &pset->permitted_user[i]; |
4182 | if (open_listen_match_streamlocal(fp, path)) { | 4309 | if (open_listen_match_streamlocal(perm, path)) { |
4183 | return connect_to(ssh, | 4310 | return connect_to(ssh, |
4184 | fp->host_to_connect, fp->port_to_connect, | 4311 | perm->host_to_connect, perm->port_to_connect, |
4185 | ctype, rname); | 4312 | ctype, rname); |
4186 | } | 4313 | } |
4187 | } | 4314 | } |
@@ -4196,28 +4323,29 @@ channel_connect_to_port(struct ssh *ssh, const char *host, u_short port, | |||
4196 | char *ctype, char *rname, int *reason, const char **errmsg) | 4323 | char *ctype, char *rname, int *reason, const char **errmsg) |
4197 | { | 4324 | { |
4198 | struct ssh_channels *sc = ssh->chanctxt; | 4325 | struct ssh_channels *sc = ssh->chanctxt; |
4326 | struct permission_set *pset = &sc->local_perms; | ||
4199 | struct channel_connect cctx; | 4327 | struct channel_connect cctx; |
4200 | Channel *c; | 4328 | Channel *c; |
4201 | u_int i, permit, permit_adm = 1; | 4329 | u_int i, permit, permit_adm = 1; |
4202 | int sock; | 4330 | int sock; |
4203 | ForwardPermission *fp; | 4331 | struct permission *perm; |
4204 | 4332 | ||
4205 | permit = sc->all_opens_permitted; | 4333 | permit = pset->all_permitted; |
4206 | if (!permit) { | 4334 | if (!permit) { |
4207 | for (i = 0; i < sc->num_permitted_opens; i++) { | 4335 | for (i = 0; i < pset->num_permitted_user; i++) { |
4208 | fp = &sc->permitted_opens[i]; | 4336 | perm = &pset->permitted_user[i]; |
4209 | if (open_match(fp, host, port)) { | 4337 | if (open_match(perm, host, port)) { |
4210 | permit = 1; | 4338 | permit = 1; |
4211 | break; | 4339 | break; |
4212 | } | 4340 | } |
4213 | } | 4341 | } |
4214 | } | 4342 | } |
4215 | 4343 | ||
4216 | if (sc->num_adm_permitted_opens > 0) { | 4344 | if (pset->num_permitted_admin > 0) { |
4217 | permit_adm = 0; | 4345 | permit_adm = 0; |
4218 | for (i = 0; i < sc->num_adm_permitted_opens; i++) { | 4346 | for (i = 0; i < pset->num_permitted_admin; i++) { |
4219 | fp = &sc->permitted_adm_opens[i]; | 4347 | perm = &pset->permitted_admin[i]; |
4220 | if (open_match(fp, host, port)) { | 4348 | if (open_match(perm, host, port)) { |
4221 | permit_adm = 1; | 4349 | permit_adm = 1; |
4222 | break; | 4350 | break; |
4223 | } | 4351 | } |
@@ -4255,25 +4383,26 @@ channel_connect_to_path(struct ssh *ssh, const char *path, | |||
4255 | char *ctype, char *rname) | 4383 | char *ctype, char *rname) |
4256 | { | 4384 | { |
4257 | struct ssh_channels *sc = ssh->chanctxt; | 4385 | struct ssh_channels *sc = ssh->chanctxt; |
4386 | struct permission_set *pset = &sc->local_perms; | ||
4258 | u_int i, permit, permit_adm = 1; | 4387 | u_int i, permit, permit_adm = 1; |
4259 | ForwardPermission *fp; | 4388 | struct permission *perm; |
4260 | 4389 | ||
4261 | permit = sc->all_opens_permitted; | 4390 | permit = pset->all_permitted; |
4262 | if (!permit) { | 4391 | if (!permit) { |
4263 | for (i = 0; i < sc->num_permitted_opens; i++) { | 4392 | for (i = 0; i < pset->num_permitted_user; i++) { |
4264 | fp = &sc->permitted_opens[i]; | 4393 | perm = &pset->permitted_user[i]; |
4265 | if (open_match(fp, path, PORT_STREAMLOCAL)) { | 4394 | if (open_match(perm, path, PORT_STREAMLOCAL)) { |
4266 | permit = 1; | 4395 | permit = 1; |
4267 | break; | 4396 | break; |
4268 | } | 4397 | } |
4269 | } | 4398 | } |
4270 | } | 4399 | } |
4271 | 4400 | ||
4272 | if (sc->num_adm_permitted_opens > 0) { | 4401 | if (pset->num_permitted_admin > 0) { |
4273 | permit_adm = 0; | 4402 | permit_adm = 0; |
4274 | for (i = 0; i < sc->num_adm_permitted_opens; i++) { | 4403 | for (i = 0; i < pset->num_permitted_admin; i++) { |
4275 | fp = &sc->permitted_adm_opens[i]; | 4404 | perm = &pset->permitted_admin[i]; |
4276 | if (open_match(fp, path, PORT_STREAMLOCAL)) { | 4405 | if (open_match(perm, path, PORT_STREAMLOCAL)) { |
4277 | permit_adm = 1; | 4406 | permit_adm = 1; |
4278 | break; | 4407 | break; |
4279 | } | 4408 | } |