Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dbclient: support -o StrictHostKeyChecking #269

Merged
merged 18 commits into from
Apr 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 44 additions & 8 deletions manpages/dbclient.1
Original file line number Diff line number Diff line change
Expand Up @@ -162,21 +162,57 @@ The following options have currently been implemented:

.RS
.TP
.B ExitOnForwardFailure
Specifies whether dbclient should terminate the connection if it cannot set up all requested local and remote port forwardings. The argument must be "yes" or "no". The default is "no".
.B BatchMode
Disable interactive prompts e.g. password prompts and host key confirmation. The argument must be "yes" or "no" (the default).
.TP
.B UseSyslog
Send dbclient log messages to syslog in addition to stderr.
.TP
.B Port
Specify a listening port, like the \fI-p\fR argument.
.B BindAddress
Specify address and port on the local machine as the source address of the connection.
.TP
.B DisableTrivialAuth
Disallow a server immediately
giving successful authentication (without presenting any password/pubkey prompt).
This avoids a UI confusion issue where it may appear that the user is accepting
a SSH agent prompt from their local machine, but are actually accepting a prompt
sent immediately by the remote server.
sent immediately by the remote server.
.TP
.B ExitOnForwardFailure
Specifies whether dbclient should terminate the connection if it cannot set up all requested local and remote port forwardings. The argument must be "yes" or "no" (the default).
.TP
.B ForwardAgent
Forward the authentication agent to the remote machine. The argument must be "yes" or "no" (the default).
.TP
.B GatewayPorts
Allow to remote host to connect to local forwarded ports. The argument must be "yes" or "no" (the default).
.TP
.B IdentityFile
Specify an authentication identity file path.
.TP
.B PasswordAuthentication
Allow to prompt a user for a password. If the DROPBEAR_PASSWORD env is specified then it still will be used. The argument must be "yes" (the default) or "no".
.TP
.B Port
Specify a listening port, like the \fI-p\fR argument.
.TP
.B ProxyCommand
Specify the proxy command to use to connect to the server.
.TP
.B ServerAliveInterval
Sets a timeout interval in seconds between keep-alive messages through the encrypted channel. The default is 0 e.g. disabled.
.TP
.B StrictHostKeyChecking
Use "yes" to refuse connection to hosts where the host key is not already
correct in known_hosts. Entries must be added to known_hosts manually.

Use "no" to skip the known_hosts key checking.

Use "accept-new" to add new host keys to the known_hosts and
refuse to connect if the host key has changed.

"ask" is the default.

.TP
.B UseSyslog
Send dbclient log messages to syslog in addition to stderr.
.RE
.TP
.B \-s
Expand Down
27 changes: 20 additions & 7 deletions src/cli-auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ void recv_msg_userauth_failure() {
unsigned int methlen = 0;
unsigned int partial = 0;
unsigned int i = 0;
int allow_pw_auth = 1;

TRACE(("<- MSG_USERAUTH_FAILURE"))
TRACE(("enter recv_msg_userauth_failure"))
Expand All @@ -175,6 +176,13 @@ void recv_msg_userauth_failure() {
dropbear_exit("Unexpected userauth failure");
}

/* Password authentication is only allowed in batch mode
* when a password can be provided non-interactively */
if (cli_opts.batch_mode && !getenv(DROPBEAR_PASSWORD_ENV)) {
allow_pw_auth = 0;
}
allow_pw_auth &= cli_opts.password_authentication;

/* When DROPBEAR_CLI_IMMEDIATE_AUTH is set there will be an initial response for
the "none" auth request, and then a response to the immediate auth request.
We need to be careful handling them. */
Expand Down Expand Up @@ -239,14 +247,14 @@ void recv_msg_userauth_failure() {
}
#endif
#if DROPBEAR_CLI_INTERACT_AUTH
if (strncmp(AUTH_METHOD_INTERACT, tok,
AUTH_METHOD_INTERACT_LEN) == 0) {
if (allow_pw_auth
&& strncmp(AUTH_METHOD_INTERACT, tok, AUTH_METHOD_INTERACT_LEN) == 0) {
ses.authstate.authtypes |= AUTH_TYPE_INTERACT;
}
#endif
#if DROPBEAR_CLI_PASSWORD_AUTH
if (strncmp(AUTH_METHOD_PASSWORD, tok,
AUTH_METHOD_PASSWORD_LEN) == 0) {
if (allow_pw_auth
&& strncmp(AUTH_METHOD_PASSWORD, tok, AUTH_METHOD_PASSWORD_LEN) == 0) {
ses.authstate.authtypes |= AUTH_TYPE_PASSWORD;
}
#endif
Expand Down Expand Up @@ -297,7 +305,7 @@ int cli_auth_try() {
#endif

#if DROPBEAR_CLI_INTERACT_AUTH
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_INTERACT)) {
if (!finished && cli_opts.password_authentication && (ses.authstate.authtypes & AUTH_TYPE_INTERACT)) {
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
fprintf(stderr, "Sorry, I won't let you use interactive auth unencrypted.\n");
} else {
Expand All @@ -311,7 +319,7 @@ int cli_auth_try() {
#endif

#if DROPBEAR_CLI_PASSWORD_AUTH
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_PASSWORD)) {
if (!finished && cli_opts.password_authentication && (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 {
Expand Down Expand Up @@ -347,8 +355,13 @@ char* getpass_or_cancel(const char* prompt)
return password;
}
#endif
if (cli_opts.batch_mode) {
dropbear_close("BatchMode active, no interactive session possible.");
}

password = getpass(prompt);
if (!cli_opts.batch_mode) {
password = getpass(prompt);
}

/* 0x03 is a ctrl-c character in the buffer. */
if (password == NULL || strchr(password, '\3') != NULL) {
Expand Down
18 changes: 16 additions & 2 deletions src/cli-kex.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,15 @@ static void ask_to_confirm(const unsigned char* keyblob, unsigned int keybloblen
int response = 'z';

fp = sign_key_fingerprint(keyblob, keybloblen);

if (!cli_opts.ask_hostkey) {
dropbear_log(LOG_INFO, "\nHost '%s' key unknown.\n(%s fingerprint %s)",
cli_opts.remotehost,
algoname,
fp);
dropbear_exit("Not accepted automatically");
}

if (cli_opts.always_accept_key) {
dropbear_log(LOG_INFO, "\nHost '%s' key accepted unconditionally.\n(%s fingerprint %s)\n",
cli_opts.remotehost,
Expand All @@ -217,12 +226,17 @@ static void ask_to_confirm(const unsigned char* keyblob, unsigned int keybloblen
m_free(fp);
return;
}
fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(%s fingerprint %s)\nDo you want to continue connecting? (y/n) ",

fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(%s fingerprint %s)\n",
cli_opts.remotehost,
algoname,
fp);
m_free(fp);
if (cli_opts.batch_mode) {
dropbear_exit("Didn't validate host key");
}

fprintf(stderr, "Do you want to continue connecting? (y/n) ");
tty = fopen(_PATH_TTY, "r");
if (tty) {
response = getc(tty);
Expand Down Expand Up @@ -399,7 +413,7 @@ static void checkhostkey(const unsigned char* keyblob, unsigned int keybloblen)
goto out;
}

if (!cli_opts.always_accept_key) {
if (!cli_opts.no_hostkey_check) {
/* put the new entry in the file */
fseek(hostsfile, 0, SEEK_END); /* In case it wasn't opened append */
buf_setpos(line, 0);
Expand Down
Loading
Loading