Skip to content

Commit

Permalink
Merge pull request #182 from tuoha/permitopen_authorized_keys
Browse files Browse the repository at this point in the history
Added permitopen option to authorized_keys
  • Loading branch information
mkj committed Oct 25, 2022
2 parents f7d306e + 1e4d64d commit 5284a3d
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 0 deletions.
13 changes: 13 additions & 0 deletions auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "includes.h"
#include "signkey.h"
#include "chansession.h"
#include "list.h"

void svr_authinitialise(void);

Expand All @@ -45,6 +46,7 @@ int svr_pubkey_allows_agentfwd(void);
int svr_pubkey_allows_tcpfwd(void);
int svr_pubkey_allows_x11fwd(void);
int svr_pubkey_allows_pty(void);
int svr_pubkey_allows_local_tcpfwd(const char *host, unsigned int port);
void svr_pubkey_set_forced_command(struct ChanSess *chansess);
void svr_pubkey_options_cleanup(void);
int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filename);
Expand All @@ -54,6 +56,9 @@ int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filena
#define svr_pubkey_allows_tcpfwd() 1
#define svr_pubkey_allows_x11fwd() 1
#define svr_pubkey_allows_pty() 1
static inline int svr_pubkey_allows_local_tcpfwd(const char *host, unsigned int port)
{ (void)host; (void)port; return 1; }

static inline void svr_pubkey_set_forced_command(struct ChanSess *chansess) { }
static inline void svr_pubkey_options_cleanup(void) { }
#define svr_add_pubkey_options(x,y,z) DROPBEAR_SUCCESS
Expand Down Expand Up @@ -93,6 +98,7 @@ void cli_auth_pubkey_cleanup(void);
#define AUTH_METHOD_INTERACT "keyboard-interactive"
#define AUTH_METHOD_INTERACT_LEN 20

#define PUBKEY_OPTIONS_ANY_PORT UINT_MAX


/* This structure is shared between server and client - it contains
Expand Down Expand Up @@ -139,6 +145,13 @@ struct PubKeyOptions {
int no_pty_flag;
/* "command=" option. */
char * forced_command;
/* "permitopen=" option */
m_list *permit_open_destinations;
};

struct PermitTCPFwdEntry {
char *host;
unsigned int port;
};
#endif

Expand Down
8 changes: 8 additions & 0 deletions dropbear.8
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,14 @@ same functionality with other means even if no-pty is set.
.B restrict
Applies all the no- restrictions listed above.

.TP
.B permitopen=\fR"\fIhost:port\fR"
Restrict local port forwarding so that connection is allowed only to the
specified host and port. Multiple permitopen options separated by commas
can be set in authorized_keys. Wildcard character ('*') may be used in
port specification for matching any port. Hosts must be literal domain names or
IP addresses.

.TP
.B command=\fR"\fIforced_command\fR"
Disregard the command provided by the user and always run \fIforced_command\fR.
Expand Down
81 changes: 81 additions & 0 deletions svr-authpubkeyoptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include "dbutil.h"
#include "signkey.h"
#include "auth.h"
#include "runopts.h"

#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT

Expand Down Expand Up @@ -88,6 +89,29 @@ int svr_pubkey_allows_pty() {
return 1;
}

/* Returns 1 if pubkey allows local tcp fowarding to the provided destination,
* 0 otherwise */
int svr_pubkey_allows_local_tcpfwd(const char *host, unsigned int port) {
if (ses.authstate.pubkey_options
&& ses.authstate.pubkey_options->permit_open_destinations) {
m_list_elem *iter = ses.authstate.pubkey_options->permit_open_destinations->first;
while (iter) {
struct PermitTCPFwdEntry *entry = (struct PermitTCPFwdEntry*)iter->item;
if (strcmp(entry->host, host) == 0) {
if ((entry->port == PUBKEY_OPTIONS_ANY_PORT) || (entry->port == port)) {
return 1;
}
}

iter = iter->next;
}

return 0;
}

return 1;
}

/* Set chansession command to the one forced
* by any 'command' public key option. */
void svr_pubkey_set_forced_command(struct ChanSess *chansess) {
Expand All @@ -113,6 +137,16 @@ void svr_pubkey_options_cleanup() {
if (ses.authstate.pubkey_options->forced_command) {
m_free(ses.authstate.pubkey_options->forced_command);
}
if (ses.authstate.pubkey_options->permit_open_destinations) {
m_list_elem *iter = ses.authstate.pubkey_options->permit_open_destinations->first;
while (iter) {
struct PermitTCPFwdEntry *entry = (struct PermitTCPFwdEntry*)list_remove(iter);
m_free(entry->host);
m_free(entry);
iter = ses.authstate.pubkey_options->permit_open_destinations->first;
}
m_free(ses.authstate.pubkey_options->permit_open_destinations);
}
m_free(ses.authstate.pubkey_options);
}
if (ses.authstate.pubkey_info) {
Expand Down Expand Up @@ -205,6 +239,53 @@ int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filena
dropbear_log(LOG_WARNING, "Badly formatted command= authorized_keys option");
goto bad_option;
}
if (match_option(options_buf, "permitopen=\"") == DROPBEAR_SUCCESS) {
int valid_option = 0;
const unsigned char* permitopen_start = buf_getptr(options_buf, 0);

if (!ses.authstate.pubkey_options->permit_open_destinations) {
ses.authstate.pubkey_options->permit_open_destinations = list_new();
}

while (options_buf->pos < options_buf->len) {
const char c = buf_getbyte(options_buf);
if (c == '"') {
char *spec = NULL;
char *portstring = NULL;
const int permitopen_len = buf_getptr(options_buf, 0) - permitopen_start;
struct PermitTCPFwdEntry *entry =
(struct PermitTCPFwdEntry*)m_malloc(sizeof(struct PermitTCPFwdEntry));

list_append(ses.authstate.pubkey_options->permit_open_destinations, entry);
spec = m_malloc(permitopen_len);
memcpy(spec, permitopen_start, permitopen_len - 1);
spec[permitopen_len - 1] = '\0';
if ((split_address_port(spec, &entry->host, &portstring) == DROPBEAR_SUCCESS)
&& entry->host && portstring) {
if (strcmp(portstring, "*") == 0) {
valid_option = 1;
entry->port = PUBKEY_OPTIONS_ANY_PORT;
TRACE(("local port forwarding allowed to host '%s'", entry->host));
} else if (m_str_to_uint(portstring, &entry->port) == DROPBEAR_SUCCESS) {
valid_option = 1;
TRACE(("local port forwarding allowed to host '%s' and port '%u'",
entry->host, entry->port));
}
}

m_free(spec);
m_free(portstring);
break;
}
}

if (valid_option) {
goto next_option;
} else {
dropbear_log(LOG_WARNING, "Badly formatted permitopen= authorized_keys option");
goto bad_option;
}
}

next_option:
/*
Expand Down
5 changes: 5 additions & 0 deletions svr-tcpfwd.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,11 @@ static int newtcpdirect(struct Channel * channel) {
goto out;
}

if (!svr_pubkey_allows_local_tcpfwd(desthost, destport)) {
TRACE(("leave newtcpdirect: local tcp forwarding not permitted to requested destination"));
goto out;
}

snprintf(portstring, sizeof(portstring), "%u", destport);
channel->conn_pending = connect_remote(desthost, portstring, channel_connect_done,
channel, NULL, NULL, DROPBEAR_PRIO_NORMAL);
Expand Down

0 comments on commit 5284a3d

Please sign in to comment.