diff options
Diffstat (limited to 'svr-authpubkeyoptions.c')
-rw-r--r-- | svr-authpubkeyoptions.c | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/svr-authpubkeyoptions.c b/svr-authpubkeyoptions.c index 447f4b7..e25bcf1 100644 --- a/svr-authpubkeyoptions.c +++ b/svr-authpubkeyoptions.c @@ -46,6 +46,7 @@ #include "dbutil.h" #include "signkey.h" #include "auth.h" +#include "runopts.h" #if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT @@ -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) { @@ -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) { @@ -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: /* |