mirror of
https://github.com/clearml/dropbear
synced 2025-06-16 19:28:49 +00:00
Merge remote-tracking branch 'refs/remotes/origin/master'
This commit is contained in:
commit
9d320a73be
13
auth.h
13
auth.h
@ -28,6 +28,7 @@
|
|||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
#include "signkey.h"
|
#include "signkey.h"
|
||||||
#include "chansession.h"
|
#include "chansession.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
void svr_authinitialise(void);
|
void svr_authinitialise(void);
|
||||||
|
|
||||||
@ -45,6 +46,7 @@ int svr_pubkey_allows_agentfwd(void);
|
|||||||
int svr_pubkey_allows_tcpfwd(void);
|
int svr_pubkey_allows_tcpfwd(void);
|
||||||
int svr_pubkey_allows_x11fwd(void);
|
int svr_pubkey_allows_x11fwd(void);
|
||||||
int svr_pubkey_allows_pty(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_set_forced_command(struct ChanSess *chansess);
|
||||||
void svr_pubkey_options_cleanup(void);
|
void svr_pubkey_options_cleanup(void);
|
||||||
int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filename);
|
int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filename);
|
||||||
@ -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_tcpfwd() 1
|
||||||
#define svr_pubkey_allows_x11fwd() 1
|
#define svr_pubkey_allows_x11fwd() 1
|
||||||
#define svr_pubkey_allows_pty() 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_set_forced_command(struct ChanSess *chansess) { }
|
||||||
static inline void svr_pubkey_options_cleanup(void) { }
|
static inline void svr_pubkey_options_cleanup(void) { }
|
||||||
#define svr_add_pubkey_options(x,y,z) DROPBEAR_SUCCESS
|
#define svr_add_pubkey_options(x,y,z) DROPBEAR_SUCCESS
|
||||||
@ -93,6 +98,7 @@ void cli_auth_pubkey_cleanup(void);
|
|||||||
#define AUTH_METHOD_INTERACT "keyboard-interactive"
|
#define AUTH_METHOD_INTERACT "keyboard-interactive"
|
||||||
#define AUTH_METHOD_INTERACT_LEN 20
|
#define AUTH_METHOD_INTERACT_LEN 20
|
||||||
|
|
||||||
|
#define PUBKEY_OPTIONS_ANY_PORT UINT_MAX
|
||||||
|
|
||||||
|
|
||||||
/* This structure is shared between server and client - it contains
|
/* This structure is shared between server and client - it contains
|
||||||
@ -139,6 +145,13 @@ struct PubKeyOptions {
|
|||||||
int no_pty_flag;
|
int no_pty_flag;
|
||||||
/* "command=" option. */
|
/* "command=" option. */
|
||||||
char * forced_command;
|
char * forced_command;
|
||||||
|
/* "permitopen=" option */
|
||||||
|
m_list *permit_open_destinations;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PermitTCPFwdEntry {
|
||||||
|
char *host;
|
||||||
|
unsigned int port;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
24
cli-auth.c
24
cli-auth.c
@ -296,18 +296,6 @@ int cli_auth_try() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if DROPBEAR_CLI_PASSWORD_AUTH
|
|
||||||
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_PASSWORD)) {
|
|
||||||
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
|
|
||||||
fprintf(stderr, "Sorry, I won't let you use password auth unencrypted.\n");
|
|
||||||
} else {
|
|
||||||
cli_auth_password();
|
|
||||||
finished = 1;
|
|
||||||
cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if DROPBEAR_CLI_INTERACT_AUTH
|
#if DROPBEAR_CLI_INTERACT_AUTH
|
||||||
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_INTERACT)) {
|
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_INTERACT)) {
|
||||||
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
|
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
|
||||||
@ -322,6 +310,18 @@ int cli_auth_try() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if DROPBEAR_CLI_PASSWORD_AUTH
|
||||||
|
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_PASSWORD)) {
|
||||||
|
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
|
||||||
|
fprintf(stderr, "Sorry, I won't let you use password auth unencrypted.\n");
|
||||||
|
} else {
|
||||||
|
cli_auth_password();
|
||||||
|
finished = 1;
|
||||||
|
cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
TRACE(("cli_auth_try lastauthtype %d", cli_ses.lastauthtype))
|
TRACE(("cli_auth_try lastauthtype %d", cli_ses.lastauthtype))
|
||||||
|
|
||||||
if (finished) {
|
if (finished) {
|
||||||
|
@ -229,6 +229,8 @@ static void ask_to_confirm(const unsigned char* keyblob, unsigned int keybloblen
|
|||||||
fclose(tty);
|
fclose(tty);
|
||||||
} else {
|
} else {
|
||||||
response = getc(stdin);
|
response = getc(stdin);
|
||||||
|
/* flush stdin buffer */
|
||||||
|
while ((getchar()) != '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response == 'y') {
|
if (response == 'y') {
|
||||||
|
@ -144,6 +144,14 @@ same functionality with other means even if no-pty is set.
|
|||||||
.B restrict
|
.B restrict
|
||||||
Applies all the no- restrictions listed above.
|
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
|
.TP
|
||||||
.B command=\fR"\fIforced_command\fR"
|
.B command=\fR"\fIforced_command\fR"
|
||||||
Disregard the command provided by the user and always run \fIforced_command\fR.
|
Disregard the command provided by the user and always run \fIforced_command\fR.
|
||||||
|
@ -104,7 +104,7 @@ LIBTOOLFLAGS += -no-undefined
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# add in the standard FLAGS
|
# add in the standard FLAGS
|
||||||
LTM_CFLAGS += $(CFLAGS)
|
LTM_CFLAGS := $(CFLAGS) $(LTM_CFLAGS)
|
||||||
LTM_LFLAGS += $(LFLAGS)
|
LTM_LFLAGS += $(LFLAGS)
|
||||||
LTM_LDFLAGS += $(LDFLAGS)
|
LTM_LDFLAGS += $(LDFLAGS)
|
||||||
LTM_LIBTOOLFLAGS += $(LIBTOOLFLAGS)
|
LTM_LIBTOOLFLAGS += $(LIBTOOLFLAGS)
|
||||||
|
@ -829,7 +829,7 @@ utmpx_perform_login(struct logininfo *li)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
# else
|
# else
|
||||||
if (!utmpx_write_direct(li, &ut)) {
|
if (!utmpx_write_direct(li, &utx)) {
|
||||||
dropbear_log(LOG_WARNING, "utmpx_perform_login: utmp_write_direct() failed");
|
dropbear_log(LOG_WARNING, "utmpx_perform_login: utmp_write_direct() failed");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
54
packet.c
54
packet.c
@ -430,44 +430,32 @@ static buffer* buf_decompress(const buffer* buf, unsigned int len) {
|
|||||||
z_streamp zstream;
|
z_streamp zstream;
|
||||||
|
|
||||||
zstream = ses.keys->recv.zstream;
|
zstream = ses.keys->recv.zstream;
|
||||||
ret = buf_new(len);
|
/* We use RECV_MAX_PAYLOAD_LEN+1 here to ensure that
|
||||||
|
we can detect an oversized payload after inflate() */
|
||||||
|
ret = buf_new(RECV_MAX_PAYLOAD_LEN+1);
|
||||||
|
|
||||||
zstream->avail_in = len;
|
zstream->avail_in = len;
|
||||||
zstream->next_in = buf_getptr(buf, len);
|
zstream->next_in = buf_getptr(buf, len);
|
||||||
|
zstream->avail_out = ret->size;
|
||||||
|
zstream->next_out = ret->data;
|
||||||
|
|
||||||
/* decompress the payload, incrementally resizing the output buffer */
|
result = inflate(zstream, Z_SYNC_FLUSH);
|
||||||
while (1) {
|
if (result != Z_OK) {
|
||||||
|
dropbear_exit("zlib error");
|
||||||
zstream->avail_out = ret->size - ret->pos;
|
|
||||||
zstream->next_out = buf_getwriteptr(ret, zstream->avail_out);
|
|
||||||
|
|
||||||
result = inflate(zstream, Z_SYNC_FLUSH);
|
|
||||||
|
|
||||||
buf_setlen(ret, ret->size - zstream->avail_out);
|
|
||||||
buf_setpos(ret, ret->len);
|
|
||||||
|
|
||||||
if (result != Z_BUF_ERROR && result != Z_OK) {
|
|
||||||
dropbear_exit("zlib error");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zstream->avail_in == 0 &&
|
|
||||||
(zstream->avail_out != 0 || result == Z_BUF_ERROR)) {
|
|
||||||
/* we can only exit if avail_out hasn't all been used,
|
|
||||||
* and there's no remaining input */
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zstream->avail_out == 0) {
|
|
||||||
int new_size = 0;
|
|
||||||
if (ret->size >= RECV_MAX_PAYLOAD_LEN) {
|
|
||||||
/* Already been increased as large as it can go,
|
|
||||||
* yet didn't finish up the decompression */
|
|
||||||
dropbear_exit("bad packet, oversized decompressed");
|
|
||||||
}
|
|
||||||
new_size = MIN(RECV_MAX_PAYLOAD_LEN, ret->size + ZLIB_DECOMPRESS_INCR);
|
|
||||||
ret = buf_resize(ret, new_size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf_setlen(ret, ret->size - zstream->avail_out);
|
||||||
|
|
||||||
|
if (zstream->avail_in > 0 || ret->len > RECV_MAX_PAYLOAD_LEN) {
|
||||||
|
/* The remote side sent larger than a payload size
|
||||||
|
* of uncompressed data.
|
||||||
|
*/
|
||||||
|
dropbear_exit("bad packet, oversized decompressed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Success. All input was consumed and avail_out > 0 */
|
||||||
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#include "dbutil.h"
|
#include "dbutil.h"
|
||||||
#include "signkey.h"
|
#include "signkey.h"
|
||||||
#include "auth.h"
|
#include "auth.h"
|
||||||
|
#include "runopts.h"
|
||||||
|
|
||||||
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
|
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
|
||||||
|
|
||||||
@ -88,6 +89,29 @@ int svr_pubkey_allows_pty() {
|
|||||||
return 1;
|
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
|
/* Set chansession command to the one forced
|
||||||
* by any 'command' public key option. */
|
* by any 'command' public key option. */
|
||||||
void svr_pubkey_set_forced_command(struct ChanSess *chansess) {
|
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) {
|
if (ses.authstate.pubkey_options->forced_command) {
|
||||||
m_free(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);
|
m_free(ses.authstate.pubkey_options);
|
||||||
}
|
}
|
||||||
if (ses.authstate.pubkey_info) {
|
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");
|
dropbear_log(LOG_WARNING, "Badly formatted command= authorized_keys option");
|
||||||
goto bad_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:
|
next_option:
|
||||||
/*
|
/*
|
||||||
|
@ -289,6 +289,11 @@ static int newtcpdirect(struct Channel * channel) {
|
|||||||
goto out;
|
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);
|
snprintf(portstring, sizeof(portstring), "%u", destport);
|
||||||
channel->conn_pending = connect_remote(desthost, portstring, channel_connect_done,
|
channel->conn_pending = connect_remote(desthost, portstring, channel_connect_done,
|
||||||
channel, NULL, NULL, DROPBEAR_PRIO_NORMAL);
|
channel, NULL, NULL, DROPBEAR_PRIO_NORMAL);
|
||||||
|
Loading…
Reference in New Issue
Block a user