summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2000-10-11 20:14:41 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2000-10-11 20:14:41 +0000
commitb0db21bafca83b9f300b0f6004b89abd7fc38dcf (patch)
treefa46ea536f7ff3c12d1ab84feccac32a742d6b99 /usr.bin
parentebff282038cb5fae7bfed8e97cfcc1e3a5d53625 (diff)
add support for s/key (kbd-interactive) to ssh2, based on work by mkiernan@avantgo.com and me
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/ssh/auth.h20
-rw-r--r--usr.bin/ssh/auth2-skey.c104
-rw-r--r--usr.bin/ssh/auth2.c349
-rw-r--r--usr.bin/ssh/cli.c196
-rw-r--r--usr.bin/ssh/cli.h14
-rw-r--r--usr.bin/ssh/lib/Makefile3
-rw-r--r--usr.bin/ssh/readconf.c19
-rw-r--r--usr.bin/ssh/readconf.h4
-rw-r--r--usr.bin/ssh/readpass.c82
-rw-r--r--usr.bin/ssh/servconf.c12
-rw-r--r--usr.bin/ssh/servconf.h3
-rw-r--r--usr.bin/ssh/ssh.h4
-rw-r--r--usr.bin/ssh/sshconnect2.c162
-rw-r--r--usr.bin/ssh/sshd/Makefile2
-rw-r--r--usr.bin/ssh/sshd_config1
15 files changed, 758 insertions, 217 deletions
diff --git a/usr.bin/ssh/auth.h b/usr.bin/ssh/auth.h
index 65bf7ae1012..c4a8ac54407 100644
--- a/usr.bin/ssh/auth.h
+++ b/usr.bin/ssh/auth.h
@@ -24,17 +24,29 @@
#ifndef AUTH_H
#define AUTH_H
+typedef struct Authctxt Authctxt;
+struct Authctxt {
+ int success;
+ int valid;
+ int attempt;
+ char *user;
+ char *service;
+ struct passwd *pw;
+};
+
void do_authentication(void);
void do_authentication2(void);
-struct passwd *
-auth_get_user(void);
+void userauth_log(Authctxt *authctxt, int authenticated, char *method);
+void userauth_reply(Authctxt *authctxt, int authenticated);
+
+int auth2_skey(Authctxt *authctxt);
-int allowed_user(struct passwd * pw);
+int allowed_user(struct passwd * pw);
+struct passwd * auth_get_user(void);
#define AUTH_FAIL_MAX 6
#define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)
#define AUTH_FAIL_MSG "Too many authentication failures for %.100s"
#endif
-
diff --git a/usr.bin/ssh/auth2-skey.c b/usr.bin/ssh/auth2-skey.c
new file mode 100644
index 00000000000..9de08fc09cf
--- /dev/null
+++ b/usr.bin/ssh/auth2-skey.c
@@ -0,0 +1,104 @@
+#include "includes.h"
+RCSID("$OpenBSD: auth2-skey.c,v 1.1 2000/10/11 20:14:38 markus Exp $");
+
+#include "ssh.h"
+#include "ssh2.h"
+#include "auth.h"
+#include "packet.h"
+#include "xmalloc.h"
+#include "dispatch.h"
+
+void send_userauth_into_request(Authctxt *authctxt, int echo);
+void input_userauth_info_response(int type, int plen, void *ctxt);
+
+/*
+ * try skey authentication, always return -1 (= postponed) since we have to
+ * wait for the s/key response.
+ */
+int
+auth2_skey(Authctxt *authctxt)
+{
+ send_userauth_into_request(authctxt, 0);
+ dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, &input_userauth_info_response);
+ return -1;
+}
+
+void
+send_userauth_into_request(Authctxt *authctxt, int echo)
+{
+ int retval = -1;
+ struct skey skey;
+ char challenge[SKEY_MAX_CHALLENGE];
+ char *fake;
+
+ if (authctxt->user == NULL)
+ fatal("send_userauth_into_request: internal error: no user");
+
+ /* get skey challenge */
+ if (authctxt->valid)
+ retval = skeychallenge(&skey, authctxt->user, challenge);
+
+ if (retval == -1) {
+ fake = skey_fake_keyinfo(authctxt->user);
+ strlcpy(challenge, fake, sizeof challenge);
+ }
+ /* send our info request */
+ packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
+ packet_put_cstring("S/Key Authentication"); /* Name */
+ packet_put_cstring(challenge); /* Instruction */
+ packet_put_cstring(""); /* Language */
+ packet_put_int(1); /* Number of prompts */
+ packet_put_cstring(echo ?
+ "Response [Echo]: ": "Response: "); /* Prompt */
+ packet_put_char(echo); /* Echo */
+ packet_send();
+ packet_write_wait();
+ memset(challenge, 'c', sizeof challenge);
+}
+
+void
+input_userauth_info_response(int type, int plen, void *ctxt)
+{
+ Authctxt *authctxt = ctxt;
+ int authenticated = 0;
+ unsigned int nresp, rlen;
+ char *resp, *method;
+
+ if (authctxt == NULL)
+ fatal("input_userauth_info_response: no authentication context");
+
+ if (authctxt->attempt++ >= AUTH_FAIL_MAX)
+ packet_disconnect("too many failed userauth_requests");
+
+ nresp = packet_get_int();
+ if (nresp == 1) {
+ /* we only support s/key and assume s/key for nresp == 1 */
+ method = "s/key";
+ resp = packet_get_string(&rlen);
+ packet_done();
+ if (strlen(resp) == 0) {
+ /*
+ * if we received a null response, resend prompt with
+ * echo enabled
+ */
+ authenticated = -1;
+ userauth_log(authctxt, authenticated, method);
+ send_userauth_into_request(authctxt, 1);
+ } else {
+ /* verify skey response */
+ if (authctxt->valid &&
+ skey_haskey(authctxt->pw->pw_name) == 0 &&
+ skey_passcheck(authctxt->pw->pw_name, resp) != -1) {
+ authenticated = 1;
+ } else {
+ authenticated = 0;
+ }
+ memset(resp, 'r', rlen);
+ /* unregister callback */
+ dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
+ userauth_log(authctxt, authenticated, method);
+ userauth_reply(authctxt, authenticated);
+ }
+ xfree(resp);
+ }
+}
diff --git a/usr.bin/ssh/auth2.c b/usr.bin/ssh/auth2.c
index 7006bfeab06..2d05a2f2e93 100644
--- a/usr.bin/ssh/auth2.c
+++ b/usr.bin/ssh/auth2.c
@@ -23,7 +23,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: auth2.c,v 1.17 2000/10/11 19:59:52 markus Exp $");
+RCSID("$OpenBSD: auth2.c,v 1.18 2000/10/11 20:14:38 markus Exp $");
#include <openssl/dsa.h>
#include <openssl/rsa.h>
@@ -57,49 +57,72 @@ extern ServerOptions options;
extern unsigned char *session_id2;
extern int session_id2_len;
+static Authctxt *x_authctxt = NULL;
+static int one = 1;
+
+typedef struct Authmethod Authmethod;
+struct Authmethod {
+ char *name;
+ int (*userauth)(Authctxt *authctxt);
+ int *enabled;
+};
+
/* protocol */
void input_service_request(int type, int plen, void *ctxt);
void input_userauth_request(int type, int plen, void *ctxt);
void protocol_error(int type, int plen, void *ctxt);
-/* auth */
-int ssh2_auth_none(struct passwd *pw);
-int ssh2_auth_password(struct passwd *pw);
-int ssh2_auth_pubkey(struct passwd *pw, char *service);
/* helper */
-struct passwd* auth_set_user(char *u, char *s);
+Authmethod *authmethod_lookup(const char *name);
+struct passwd *pwcopy(struct passwd *pw);
int user_dsa_key_allowed(struct passwd *pw, Key *key);
+char *authmethods_get(void);
-typedef struct Authctxt Authctxt;
-struct Authctxt {
- char *user;
- char *service;
- struct passwd pw;
- int valid;
+/* auth */
+int userauth_none(Authctxt *authctxt);
+int userauth_passwd(Authctxt *authctxt);
+int userauth_pubkey(Authctxt *authctxt);
+int userauth_kbdint(Authctxt *authctxt);
+
+Authmethod authmethods[] = {
+ {"none",
+ userauth_none,
+ &one},
+ {"publickey",
+ userauth_pubkey,
+ &options.dsa_authentication},
+ {"keyboard-interactive",
+ userauth_kbdint,
+ &options.kbd_interactive_authentication},
+ {"password",
+ userauth_passwd,
+ &options.password_authentication},
+ {NULL, NULL, NULL}
};
-static Authctxt *authctxt = NULL;
-static int userauth_success = 0;
/*
- * loop until userauth_success == TRUE
+ * loop until authctxt->success == TRUE
*/
void
do_authentication2()
{
- /* turn off skey/kerberos, not supported by SSH2 */
-#ifdef SKEY
- options.skey_authentication = 0;
-#endif
+ Authctxt *authctxt = xmalloc(sizeof(*authctxt));
+ memset(authctxt, 'a', sizeof(*authctxt));
+ authctxt->valid = 0;
+ authctxt->attempt = 0;
+ authctxt->success = 0;
+ x_authctxt = authctxt; /*XXX*/
+
#ifdef KRB4
+ /* turn off kerberos, not supported by SSH2 */
options.kerberos_authentication = 0;
#endif
-
dispatch_init(&protocol_error);
dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
- dispatch_run(DISPATCH_BLOCK, &userauth_success, NULL);
+ dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
do_authenticated2();
}
@@ -116,13 +139,17 @@ protocol_error(int type, int plen, void *ctxt)
void
input_service_request(int type, int plen, void *ctxt)
{
+ Authctxt *authctxt = ctxt;
unsigned int len;
int accept = 0;
char *service = packet_get_string(&len);
packet_done();
+ if (authctxt == NULL)
+ fatal("input_service_request: no authctxt");
+
if (strcmp(service, "ssh-userauth") == 0) {
- if (!userauth_success) {
+ if (!authctxt->success) {
accept = 1;
/* now we can handle user-auth requests */
dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
@@ -145,45 +172,87 @@ input_service_request(int type, int plen, void *ctxt)
void
input_userauth_request(int type, int plen, void *ctxt)
{
- static void (*authlog) (const char *fmt,...) = verbose;
- static int attempt = 0;
- unsigned int len;
+ Authctxt *authctxt = ctxt;
+ Authmethod *m = NULL;
+ char *user, *service, *method;
int authenticated = 0;
- char *user, *service, *method, *authmsg = NULL;
- struct passwd *pw;
- if (++attempt == AUTH_FAIL_MAX)
+ if (authctxt == NULL)
+ fatal("input_userauth_request: no authctxt");
+ if (authctxt->attempt++ >= AUTH_FAIL_MAX)
packet_disconnect("too many failed userauth_requests");
- user = packet_get_string(&len);
- service = packet_get_string(&len);
- method = packet_get_string(&len);
+ user = packet_get_string(NULL);
+ service = packet_get_string(NULL);
+ method = packet_get_string(NULL);
debug("userauth-request for user %s service %s method %s", user, service, method);
-
- /* XXX we only allow the ssh-connection service */
- pw = auth_set_user(user, service);
- if (pw && strcmp(service, "ssh-connection")==0) {
- if (strcmp(method, "none") == 0) {
- authenticated = ssh2_auth_none(pw);
- } else if (strcmp(method, "password") == 0) {
- authenticated = ssh2_auth_password(pw);
- } else if (strcmp(method, "publickey") == 0) {
- authenticated = ssh2_auth_pubkey(pw, service);
+ debug("attempt #%d", authctxt->attempt);
+
+ if (authctxt->attempt == 1) {
+ /* setup auth context */
+ struct passwd *pw = NULL;
+ setproctitle("%s", user);
+ pw = getpwnam(user);
+ if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) {
+ authctxt->pw = pwcopy(pw);
+ authctxt->valid = 1;
+ debug2("input_userauth_request: setting up authctxt for %s", user);
+ } else {
+ log("input_userauth_request: illegal user %s", user);
}
+ authctxt->user = xstrdup(user);
+ authctxt->service = xstrdup(service);
+ } else if (authctxt->valid) {
+ if (strcmp(user, authctxt->user) != 0 ||
+ strcmp(service, authctxt->service) != 0) {
+ log("input_userauth_request: missmatch: (%s,%s)!=(%s,%s)",
+ user, service, authctxt->user, authctxt->service);
+ authctxt->valid = 0;
+ }
+ }
+
+ m = authmethod_lookup(method);
+ if (m != NULL) {
+ debug2("input_userauth_request: try method %s", method);
+ authenticated = m->userauth(authctxt);
+ } else {
+ debug2("input_userauth_request: unsupported method %s", method);
+ }
+ if (!authctxt->valid && authenticated == 1) {
+ log("input_userauth_request: INTERNAL ERROR: authenticated invalid user %s service %s", user, method);
+ authenticated = 0;
}
- if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
+
+ /* Special handling for root */
+ if (authenticated == 1 &&
+ authctxt->valid && authctxt->pw->pw_uid == 0 && !options.permit_root_login) {
authenticated = 0;
- log("ROOT LOGIN REFUSED FROM %.200s",
- get_canonical_hostname());
+ log("ROOT LOGIN REFUSED FROM %.200s", get_canonical_hostname());
}
+ /* Log before sending the reply */
+ userauth_log(authctxt, authenticated, method);
+ userauth_reply(authctxt, authenticated);
+
+ xfree(service);
+ xfree(user);
+ xfree(method);
+}
+
+
+void
+userauth_log(Authctxt *authctxt, int authenticated, char *method)
+{
+ void (*authlog) (const char *fmt,...) = verbose;
+ char *user = NULL, *authmsg = NULL;
+
/* Raise logging level */
if (authenticated == 1 ||
- attempt == AUTH_FAIL_LOG ||
+ !authctxt->valid ||
+ authctxt->attempt >= AUTH_FAIL_LOG ||
strcmp(method, "password") == 0)
authlog = log;
- /* Log before sending the reply */
if (authenticated == 1) {
authmsg = "Accepted";
} else if (authenticated == 0) {
@@ -191,13 +260,24 @@ input_userauth_request(int type, int plen, void *ctxt)
} else {
authmsg = "Postponed";
}
+
+ if (authctxt->valid) {
+ user = authctxt->pw->pw_uid == 0 ? "ROOT" : authctxt->user;
+ } else {
+ user = "NOUSER";
+ }
+
authlog("%s %s for %.200s from %.200s port %d ssh2",
- authmsg,
- method,
- pw && pw->pw_uid == 0 ? "ROOT" : user,
- get_remote_ipaddr(),
- get_remote_port());
+ authmsg,
+ method,
+ user,
+ get_remote_ipaddr(),
+ get_remote_port());
+}
+void
+userauth_reply(Authctxt *authctxt, int authenticated)
+{
/* XXX todo: check if multiple auth methods are needed */
if (authenticated == 1) {
/* turn off userauth */
@@ -206,28 +286,33 @@ input_userauth_request(int type, int plen, void *ctxt)
packet_send();
packet_write_wait();
/* now we can break out */
- userauth_success = 1;
+ authctxt->success = 1;
} else if (authenticated == 0) {
+ char *methods = authmethods_get();
packet_start(SSH2_MSG_USERAUTH_FAILURE);
- packet_put_cstring("publickey,password"); /* XXX dynamic */
- packet_put_char(0); /* XXX partial success, unused */
+ packet_put_cstring(methods);
+ packet_put_char(0); /* XXX partial success, unused */
packet_send();
packet_write_wait();
+ xfree(methods);
+ } else {
+ /* do nothing, we did already send a reply */
}
-
- xfree(service);
- xfree(user);
- xfree(method);
}
int
-ssh2_auth_none(struct passwd *pw)
+userauth_none(Authctxt *authctxt)
{
+ /* disable method "none", only allowed one time */
+ Authmethod *m = authmethod_lookup("none");
+ if (m != NULL)
+ m->enabled = NULL;
packet_done();
- return auth_password(pw, "");
+ return authctxt->valid ? auth_password(authctxt->pw, "") : 0;
}
+
int
-ssh2_auth_password(struct passwd *pw)
+userauth_passwd(Authctxt *authctxt)
{
char *password;
int authenticated = 0;
@@ -238,15 +323,38 @@ ssh2_auth_password(struct passwd *pw)
log("password change not supported");
password = packet_get_string(&len);
packet_done();
- if (options.password_authentication &&
- auth_password(pw, password) == 1)
+ if (authctxt->valid &&
+ auth_password(authctxt->pw, password) == 1)
authenticated = 1;
memset(password, 0, len);
xfree(password);
return authenticated;
}
+
int
-ssh2_auth_pubkey(struct passwd *pw, char *service)
+userauth_kbdint(Authctxt *authctxt)
+{
+ int authenticated = 0;
+ char *lang = NULL;
+ char *devs = NULL;
+
+ lang = packet_get_string(NULL);
+ devs = packet_get_string(NULL);
+ packet_done();
+
+ debug("keyboard-interactive language %s devs %s", lang, devs);
+#ifdef SKEY
+ /* XXX hardcoded, we should look at devs */
+ if (options.skey_authentication != 0)
+ authenticated = auth2_skey(authctxt);
+#endif
+ xfree(lang);
+ xfree(devs);
+ return authenticated;
+}
+
+int
+userauth_pubkey(Authctxt *authctxt)
{
Buffer b;
Key *key;
@@ -255,15 +363,15 @@ ssh2_auth_pubkey(struct passwd *pw, char *service)
int have_sig;
int authenticated = 0;
- if (options.dsa_authentication == 0) {
- debug("pubkey auth disabled");
+ if (!authctxt->valid) {
+ debug2("userauth_pubkey: disabled because of invalid user");
return 0;
}
have_sig = packet_get_char();
pkalg = packet_get_string(&alen);
if (strcmp(pkalg, KEX_DSS) != 0) {
- xfree(pkalg);
log("bad pkalg %s", pkalg); /*XXX*/
+ xfree(pkalg);
return 0;
}
pkblob = packet_get_string(&blen);
@@ -280,11 +388,11 @@ ssh2_auth_pubkey(struct passwd *pw, char *service)
}
/* reconstruct packet */
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
- buffer_put_cstring(&b, pw->pw_name);
+ buffer_put_cstring(&b, authctxt->user);
buffer_put_cstring(&b,
datafellows & SSH_BUG_PUBKEYAUTH ?
"ssh-userauth" :
- service);
+ authctxt->service);
buffer_put_cstring(&b, "publickey");
buffer_put_char(&b, have_sig);
buffer_put_cstring(&b, KEX_DSS);
@@ -293,15 +401,15 @@ ssh2_auth_pubkey(struct passwd *pw, char *service)
buffer_dump(&b);
#endif
/* test for correct signature */
- if (user_dsa_key_allowed(pw, key) &&
+ if (user_dsa_key_allowed(authctxt->pw, key) &&
dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
authenticated = 1;
buffer_clear(&b);
xfree(sig);
} else {
+ debug("test whether pkalg/pkblob are acceptable");
packet_done();
- debug("test key...");
- /* test whether pkalg/pkblob are acceptable */
+
/* XXX fake reply and always send PK_OK ? */
/*
* XXX this allows testing whether a user is allowed
@@ -310,7 +418,7 @@ ssh2_auth_pubkey(struct passwd *pw, char *service)
* if a user is not allowed to login. is this an
* issue? -markus
*/
- if (user_dsa_key_allowed(pw, key)) {
+ if (user_dsa_key_allowed(authctxt->pw, key)) {
packet_start(SSH2_MSG_USERAUTH_PK_OK);
packet_put_string(pkalg, alen);
packet_put_string(pkblob, blen);
@@ -328,49 +436,60 @@ ssh2_auth_pubkey(struct passwd *pw, char *service)
return authenticated;
}
-/* set and get current user */
+/* get current user */
struct passwd*
auth_get_user(void)
{
- return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
+ return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL;
}
-struct passwd*
-auth_set_user(char *u, char *s)
+#define DELIM ","
+
+char *
+authmethods_get(void)
{
- struct passwd *pw, *copy;
-
- if (authctxt == NULL) {
- authctxt = xmalloc(sizeof(*authctxt));
- authctxt->valid = 0;
- authctxt->user = xstrdup(u);
- authctxt->service = xstrdup(s);
- setproctitle("%s", u);
- pw = getpwnam(u);
- if (!pw || !allowed_user(pw)) {
- log("auth_set_user: illegal user %s", u);
- return NULL;
+ Authmethod *method = NULL;
+ unsigned int size = 0;
+ char *list;
+
+ for (method = authmethods; method->name != NULL; method++) {
+ if (strcmp(method->name, "none") == 0)
+ continue;
+ if (method->enabled != NULL && *(method->enabled) != 0) {
+ if (size != 0)
+ size += strlen(DELIM);
+ size += strlen(method->name);
}
- copy = &authctxt->pw;
- memset(copy, 0, sizeof(*copy));
- copy->pw_name = xstrdup(pw->pw_name);
- copy->pw_passwd = xstrdup(pw->pw_passwd);
- copy->pw_uid = pw->pw_uid;
- copy->pw_gid = pw->pw_gid;
- copy->pw_class = xstrdup(pw->pw_class);
- copy->pw_dir = xstrdup(pw->pw_dir);
- copy->pw_shell = xstrdup(pw->pw_shell);
- authctxt->valid = 1;
- } else {
- if (strcmp(u, authctxt->user) != 0 ||
- strcmp(s, authctxt->service) != 0) {
- log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
- u, s, authctxt->user, authctxt->service);
- return NULL;
+ }
+ size++; /* trailing '\0' */
+ list = xmalloc(size);
+ list[0] = '\0';
+
+ for (method = authmethods; method->name != NULL; method++) {
+ if (strcmp(method->name, "none") == 0)
+ continue;
+ if (method->enabled != NULL && *(method->enabled) != 0) {
+ if (list[0] != '\0')
+ strlcat(list, DELIM, size);
+ strlcat(list, method->name, size);
}
}
- return auth_get_user();
+ return list;
+}
+
+Authmethod *
+authmethod_lookup(const char *name)
+{
+ Authmethod *method = NULL;
+ if (name != NULL)
+ for (method = authmethods; method->name != NULL; method++)
+ if (method->enabled != NULL &&
+ *(method->enabled) != 0 &&
+ strcmp(name, method->name) == 0)
+ return method;
+ debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
+ return NULL;
}
/* return 1 if user allows given key */
@@ -385,6 +504,9 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
struct stat st;
Key *found;
+ if (pw == NULL)
+ return 0;
+
/* Temporarily use the user's uid. */
temporarily_use_uid(pw->pw_uid);
@@ -490,3 +612,18 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
key_free(found);
return found_key;
}
+
+struct passwd *
+pwcopy(struct passwd *pw)
+{
+ struct passwd *copy = xmalloc(sizeof(*copy));
+ memset(copy, 0, sizeof(*copy));
+ copy->pw_name = xstrdup(pw->pw_name);
+ copy->pw_passwd = xstrdup(pw->pw_passwd);
+ copy->pw_uid = pw->pw_uid;
+ copy->pw_gid = pw->pw_gid;
+ copy->pw_class = xstrdup(pw->pw_class);
+ copy->pw_dir = xstrdup(pw->pw_dir);
+ copy->pw_shell = xstrdup(pw->pw_shell);
+ return copy;
+}
diff --git a/usr.bin/ssh/cli.c b/usr.bin/ssh/cli.c
new file mode 100644
index 00000000000..efc3af58b4a
--- /dev/null
+++ b/usr.bin/ssh/cli.c
@@ -0,0 +1,196 @@
+#include "includes.h"
+RCSID("$Id: cli.c,v 1.1 2000/10/11 20:14:39 markus Exp $");
+
+#include "xmalloc.h"
+#include "ssh.h"
+#include <vis.h>
+
+static int cli_input = -1;
+static int cli_output = -1;
+static int cli_from_stdin = 0;
+
+sigset_t oset;
+sigset_t nset;
+struct sigaction nsa;
+struct sigaction osa;
+struct termios ntio;
+struct termios otio;
+int echo_modified;
+
+volatile int intr;
+
+static int
+cli_open(int from_stdin)
+{
+ if (cli_input >= 0 && cli_output >= 0 && cli_from_stdin == from_stdin)
+ return 1;
+
+ if (from_stdin) {
+ if (!cli_from_stdin && cli_input >= 0) {
+ (void)close(cli_input);
+ }
+ cli_input = STDIN_FILENO;
+ cli_output = STDERR_FILENO;
+ } else {
+ cli_input = cli_output = open("/dev/tty", O_RDWR);
+ if (cli_input < 0)
+ fatal("You have no controlling tty. Cannot read passphrase.");
+ }
+
+ cli_from_stdin = from_stdin;
+
+ return cli_input >= 0 && cli_output >= 0 && cli_from_stdin == from_stdin;
+}
+
+static void
+cli_close()
+{
+ if (!cli_from_stdin && cli_input >= 0)
+ close(cli_input);
+ cli_input = -1;
+ cli_output = -1;
+ cli_from_stdin = 0;
+ return;
+}
+
+void
+intrcatch()
+{
+ intr = 1;
+}
+
+static void
+cli_echo_disable()
+{
+ sigemptyset(&nset);
+ sigaddset(&nset, SIGTSTP);
+ (void) sigprocmask(SIG_BLOCK, &nset, &oset);
+
+ intr = 0;
+
+ memset(&nsa, 0, sizeof(nsa));
+ nsa.sa_handler = intrcatch;
+ (void) sigaction(SIGINT, &nsa, &osa);
+
+ echo_modified = 0;
+ if (tcgetattr(cli_input, &otio) == 0 && (otio.c_lflag & ECHO)) {
+ echo_modified = 1;
+ ntio = otio;
+ ntio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
+ (void) tcsetattr(cli_input, TCSANOW, &ntio);
+ }
+ return;
+}
+
+static void
+cli_echo_restore()
+{
+ if (echo_modified != 0) {
+ tcsetattr(cli_input, TCSANOW, &otio);
+ echo_modified = 0;
+ }
+
+ (void) sigprocmask(SIG_SETMASK, &oset, NULL);
+ (void) sigaction(SIGINT, &osa, NULL);
+
+ if (intr != 0) {
+ kill(getpid(), SIGINT);
+ sigemptyset(&nset);
+ /* XXX tty has not neccessarily drained by now? */
+ sigsuspend(&nset);
+ intr = 0;
+ }
+ return;
+}
+
+static int
+cli_read(char* buf, int size, int echo)
+{
+ char ch = 0;
+ int i = 0;
+
+ if (!echo)
+ cli_echo_disable();
+
+ while (ch != '\n') {
+ if (read(cli_input, &ch, 1) != 1)
+ break;
+ if (ch == '\n' || intr != 0)
+ break;
+ if (i < size)
+ buf[i++] = ch;
+ }
+ buf[i] = '\0';
+
+ if (!echo)
+ cli_echo_restore();
+ if (!intr && !echo)
+ (void) write(cli_output, "\n", 1);
+ return i;
+}
+
+static int
+cli_write(char* buf, int size)
+{
+ int i, len, pos, ret = 0;
+ char *output, *p;
+
+ output = xmalloc(4*size);
+ for (p = output, i = 0; i < size; i++) {
+ if (buf[i] == '\n')
+ *p++ = buf[i];
+ else
+ p = vis(p, buf[i], 0, 0);
+ }
+ len = p - output;
+
+ for (pos = 0; pos < len; pos += ret) {
+ ret = write(cli_output, output + pos, len - pos);
+ if (ret == -1)
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Presents a prompt and returns the response allocated with xmalloc().
+ * Uses /dev/tty or stdin/out depending on arg. Optionally disables echo
+ * of response depending on arg. Tries to ensure that no other userland
+ * buffer is storing the response.
+ */
+char*
+cli_read_passphrase(char* prompt, int from_stdin, int echo_enable)
+{
+ char buf[BUFSIZ];
+ char* p;
+
+ if (!cli_open(from_stdin))
+ fatal("Cannot read passphrase.");
+
+ fflush(stdout);
+
+ cli_write(prompt, strlen(prompt));
+ cli_read(buf, sizeof buf, echo_enable);
+
+ cli_close();
+
+ p = xstrdup(buf);
+ memset(buf, 0, sizeof(buf));
+ return (p);
+}
+
+char*
+cli_prompt(char* prompt, int echo_enable)
+{
+ return cli_read_passphrase(prompt, 0, echo_enable);
+}
+
+void
+cli_mesg(char* mesg)
+{
+ cli_open(0);
+ cli_write(mesg, strlen(mesg));
+ cli_write("\n", strlen("\n"));
+ cli_close();
+ return;
+}
diff --git a/usr.bin/ssh/cli.h b/usr.bin/ssh/cli.h
new file mode 100644
index 00000000000..e33ce4a5047
--- /dev/null
+++ b/usr.bin/ssh/cli.h
@@ -0,0 +1,14 @@
+#ifndef CLI_H
+#define CLI_H
+
+/*
+ * Presents a prompt and returns the response allocated with xmalloc().
+ * Uses /dev/tty or stdin/out depending on arg. Optionally disables echo
+ * of response depending on arg. Tries to ensure that no other userland
+ * buffer is storing the response.
+ */
+char* cli_read_passphrase(char* prompt, int from_stdin, int echo_enable);
+char* cli_prompt(char* prompt, int echo_enable);
+void cli_mesg(char* mesg);
+
+#endif /* CLI_H */
diff --git a/usr.bin/ssh/lib/Makefile b/usr.bin/ssh/lib/Makefile
index 4bbe22216e2..b32b8b677a4 100644
--- a/usr.bin/ssh/lib/Makefile
+++ b/usr.bin/ssh/lib/Makefile
@@ -5,7 +5,8 @@ SRCS= authfd.c authfile.c bufaux.c buffer.c canohost.c channels.c \
cipher.c compat.c compress.c crc32.c deattack.c \
hostfile.c log.c match.c mpaux.c nchan.c packet.c readpass.c \
rsa.c tildexpand.c ttymodes.c uidswap.c xmalloc.c atomicio.c \
- key.c dispatch.c dsa.c kex.c hmac.c uuencode.c util.c
+ key.c dispatch.c dsa.c kex.c hmac.c uuencode.c util.c \
+ cli.c
NOPROFILE= yes
NOPIC= yes
diff --git a/usr.bin/ssh/readconf.c b/usr.bin/ssh/readconf.c
index 2ddf3ed1fec..717d25584a8 100644
--- a/usr.bin/ssh/readconf.c
+++ b/usr.bin/ssh/readconf.c
@@ -12,7 +12,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: readconf.c,v 1.47 2000/09/07 21:13:37 markus Exp $");
+RCSID("$OpenBSD: readconf.c,v 1.48 2000/10/11 20:14:39 markus Exp $");
#include "ssh.h"
#include "cipher.h"
@@ -103,7 +103,8 @@ typedef enum {
oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oIdentityFile2,
- oGlobalKnownHostsFile2, oUserKnownHostsFile2, oDSAAuthentication
+ oGlobalKnownHostsFile2, oUserKnownHostsFile2, oDSAAuthentication,
+ oKbdInteractiveAuthentication, oKbdInteractiveDevices
} OpCodes;
/* Textual representations of the tokens. */
@@ -119,6 +120,8 @@ static struct {
{ "useprivilegedport", oUsePrivilegedPort },
{ "rhostsauthentication", oRhostsAuthentication },
{ "passwordauthentication", oPasswordAuthentication },
+ { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
+ { "kbdinteractivedevices", oKbdInteractiveDevices },
{ "rsaauthentication", oRSAAuthentication },
{ "dsaauthentication", oDSAAuthentication },
{ "skeyauthentication", oSkeyAuthentication },
@@ -288,6 +291,14 @@ parse_flag:
intptr = &options->password_authentication;
goto parse_flag;
+ case oKbdInteractiveAuthentication:
+ intptr = &options->kbd_interactive_authentication;
+ goto parse_flag;
+
+ case oKbdInteractiveDevices:
+ charptr = &options->kbd_interactive_devices;
+ goto parse_string;
+
case oDSAAuthentication:
intptr = &options->dsa_authentication;
goto parse_flag;
@@ -662,6 +673,8 @@ initialize_options(Options * options)
options->afs_token_passing = -1;
#endif
options->password_authentication = -1;
+ options->kbd_interactive_authentication = -1;
+ options->kbd_interactive_devices = NULL;
options->rhosts_rsa_authentication = -1;
options->fallback_to_rsh = -1;
options->use_rsh = -1;
@@ -732,6 +745,8 @@ fill_default_options(Options * options)
#endif /* AFS */
if (options->password_authentication == -1)
options->password_authentication = 1;
+ if (options->kbd_interactive_authentication == -1)
+ options->kbd_interactive_authentication = 0;
if (options->rhosts_rsa_authentication == -1)
options->rhosts_rsa_authentication = 1;
if (options->fallback_to_rsh == -1)
diff --git a/usr.bin/ssh/readconf.h b/usr.bin/ssh/readconf.h
index 23df57b4271..e94213fa177 100644
--- a/usr.bin/ssh/readconf.h
+++ b/usr.bin/ssh/readconf.h
@@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
-/* RCSID("$OpenBSD: readconf.h,v 1.21 2000/09/07 20:27:53 deraadt Exp $"); */
+/* RCSID("$OpenBSD: readconf.h,v 1.22 2000/10/11 20:14:39 markus Exp $"); */
#ifndef READCONF_H
#define READCONF_H
@@ -47,6 +47,8 @@ typedef struct {
#endif
int password_authentication; /* Try password
* authentication. */
+ int kbd_interactive_authentication; /* Try keyboard-interactive auth. */
+ char *kbd_interactive_devices; /* Keyboard-interactive auth devices. */
int fallback_to_rsh;/* Use rsh if cannot connect with ssh. */
int use_rsh; /* Always use rsh (don\'t try ssh). */
int batch_mode; /* Batch mode: do not ask for passwords. */
diff --git a/usr.bin/ssh/readpass.c b/usr.bin/ssh/readpass.c
index c38292f1571..f3a7dcbed27 100644
--- a/usr.bin/ssh/readpass.c
+++ b/usr.bin/ssh/readpass.c
@@ -32,88 +32,24 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: readpass.c,v 1.11 2000/06/20 01:39:44 markus Exp $");
+RCSID("$OpenBSD: readpass.c,v 1.12 2000/10/11 20:14:39 markus Exp $");
#include "xmalloc.h"
#include "ssh.h"
-
-volatile int intr;
-
-void
-intcatch()
-{
- intr = 1;
-}
+#include "cli.h"
/*
* Reads a passphrase from /dev/tty with echo turned off. Returns the
* passphrase (allocated with xmalloc), being very careful to ensure that
* no other userland buffer is storing the password.
*/
+/*
+ * Note: the funcationallity of this routing has been moved to
+ * cli_read_passphrase(). This routing remains to maintain
+ * compatibility with existing code.
+ */
char *
-read_passphrase(const char *prompt, int from_stdin)
+read_passphrase(char *prompt, int from_stdin)
{
- char buf[1024], *p, ch;
- struct termios tio, saved_tio;
- sigset_t oset, nset;
- struct sigaction sa, osa;
- int input, output, echo = 0;
-
- if (from_stdin) {
- input = STDIN_FILENO;
- output = STDERR_FILENO;
- } else
- input = output = open("/dev/tty", O_RDWR);
-
- if (input == -1)
- fatal("You have no controlling tty. Cannot read passphrase.\n");
-
- /* block signals, get terminal modes and turn off echo */
- sigemptyset(&nset);
- sigaddset(&nset, SIGTSTP);
- (void) sigprocmask(SIG_BLOCK, &nset, &oset);
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = intcatch;
- (void) sigaction(SIGINT, &sa, &osa);
-
- intr = 0;
-
- if (tcgetattr(input, &saved_tio) == 0 && (saved_tio.c_lflag & ECHO)) {
- echo = 1;
- tio = saved_tio;
- tio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
- (void) tcsetattr(input, TCSANOW, &tio);
- }
-
- fflush(stdout);
-
- (void)write(output, prompt, strlen(prompt));
- for (p = buf; read(input, &ch, 1) == 1 && ch != '\n';) {
- if (intr)
- break;
- if (p < buf + sizeof(buf) - 1)
- *p++ = ch;
- }
- *p = '\0';
- if (!intr)
- (void)write(output, "\n", 1);
-
- /* restore terminal modes and allow signals */
- if (echo)
- tcsetattr(input, TCSANOW, &saved_tio);
- (void) sigprocmask(SIG_SETMASK, &oset, NULL);
- (void) sigaction(SIGINT, &osa, NULL);
-
- if (intr) {
- kill(getpid(), SIGINT);
- sigemptyset(&nset);
- /* XXX tty has not neccessarily drained by now? */
- sigsuspend(&nset);
- }
-
- if (!from_stdin)
- (void)close(input);
- p = xstrdup(buf);
- memset(buf, 0, sizeof(buf));
- return (p);
+ return cli_read_passphrase(prompt, from_stdin, 0);
}
diff --git a/usr.bin/ssh/servconf.c b/usr.bin/ssh/servconf.c
index 81551081432..e90defe61e5 100644
--- a/usr.bin/ssh/servconf.c
+++ b/usr.bin/ssh/servconf.c
@@ -10,7 +10,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: servconf.c,v 1.51 2000/09/07 20:27:53 deraadt Exp $");
+RCSID("$OpenBSD: servconf.c,v 1.52 2000/10/11 20:14:39 markus Exp $");
#include "ssh.h"
#include "servconf.h"
@@ -61,6 +61,7 @@ initialize_server_options(ServerOptions *options)
options->afs_token_passing = -1;
#endif
options->password_authentication = -1;
+ options->kbd_interactive_authentication = -1;
#ifdef SKEY
options->skey_authentication = -1;
#endif
@@ -148,6 +149,8 @@ fill_default_server_options(ServerOptions *options)
#endif /* AFS */
if (options->password_authentication == -1)
options->password_authentication = 1;
+ if (options->kbd_interactive_authentication == -1)
+ options->kbd_interactive_authentication = 0;
#ifdef SKEY
if (options->skey_authentication == -1)
options->skey_authentication = 1;
@@ -183,7 +186,7 @@ typedef enum {
#ifdef SKEY
sSkeyAuthentication,
#endif
- sPasswordAuthentication, sListenAddress,
+ sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress,
sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset,
sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
@@ -220,6 +223,7 @@ static struct {
{ "afstokenpassing", sAFSTokenPassing },
#endif
{ "passwordauthentication", sPasswordAuthentication },
+ { "kbdinteractiveauthentication", sKbdInteractiveAuthentication },
#ifdef SKEY
{ "skeyauthentication", sSkeyAuthentication },
#endif
@@ -497,6 +501,10 @@ parse_flag:
intptr = &options->password_authentication;
goto parse_flag;
+ case sKbdInteractiveAuthentication:
+ intptr = &options->kbd_interactive_authentication;
+ goto parse_flag;
+
case sCheckMail:
intptr = &options->check_mail;
goto parse_flag;
diff --git a/usr.bin/ssh/servconf.h b/usr.bin/ssh/servconf.h
index f00a1284f55..ef0790c7beb 100644
--- a/usr.bin/ssh/servconf.h
+++ b/usr.bin/ssh/servconf.h
@@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
-/* RCSID("$OpenBSD: servconf.h,v 1.28 2000/09/07 20:27:53 deraadt Exp $"); */
+/* RCSID("$OpenBSD: servconf.h,v 1.29 2000/10/11 20:14:39 markus Exp $"); */
#ifndef SERVCONF_H
#define SERVCONF_H
@@ -78,6 +78,7 @@ typedef struct {
#endif
int password_authentication; /* If true, permit password
* authentication. */
+ int kbd_interactive_authentication; /* If true, permit */
#ifdef SKEY
int skey_authentication; /* If true, permit s/key
* authentication. */
diff --git a/usr.bin/ssh/ssh.h b/usr.bin/ssh/ssh.h
index 3092d220e58..06810e77ef2 100644
--- a/usr.bin/ssh/ssh.h
+++ b/usr.bin/ssh/ssh.h
@@ -12,7 +12,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
-/* RCSID("$OpenBSD: ssh.h,v 1.52 2000/10/11 04:02:17 provos Exp $"); */
+/* RCSID("$OpenBSD: ssh.h,v 1.53 2000/10/11 20:14:39 markus Exp $"); */
#ifndef SSH_H
#define SSH_H
@@ -381,7 +381,7 @@ int auth_rsa_challenge_dialog(RSA *pk);
* passphrase (allocated with xmalloc). Exits if EOF is encountered. If
* from_stdin is true, the passphrase will be read from stdin instead.
*/
-char *read_passphrase(const char *prompt, int from_stdin);
+char *read_passphrase(char *prompt, int from_stdin);
/*------------ Definitions for logging. -----------------------*/
diff --git a/usr.bin/ssh/sshconnect2.c b/usr.bin/ssh/sshconnect2.c
index 455850eebc6..f8bbc600322 100644
--- a/usr.bin/ssh/sshconnect2.c
+++ b/usr.bin/ssh/sshconnect2.c
@@ -23,7 +23,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: sshconnect2.c,v 1.22 2000/10/11 04:02:17 provos Exp $");
+RCSID("$OpenBSD: sshconnect2.c,v 1.23 2000/10/11 20:14:39 markus Exp $");
#include <openssl/bn.h>
#include <openssl/rsa.h>
@@ -49,6 +49,7 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.22 2000/10/11 04:02:17 provos Exp $");
#include "dsa.h"
#include "sshconnect.h"
#include "authfile.h"
+#include "cli.h"
#include "dispatch.h"
#include "authfd.h"
@@ -457,8 +458,8 @@ struct Authctxt {
const char *host;
const char *service;
AuthenticationConnection *agent;
- int success;
Authmethod *method;
+ int success;
};
struct Authmethod {
char *name; /* string to compare against server's list */
@@ -470,11 +471,16 @@ struct Authmethod {
void input_userauth_success(int type, int plen, void *ctxt);
void input_userauth_failure(int type, int plen, void *ctxt);
void input_userauth_error(int type, int plen, void *ctxt);
+void input_userauth_info_req(int type, int plen, void *ctxt);
+
+int userauth_none(Authctxt *authctxt);
int userauth_pubkey(Authctxt *authctxt);
int userauth_passwd(Authctxt *authctxt);
+int userauth_kbdint(Authctxt *authctxt);
void authmethod_clear();
-Authmethod *authmethod_get(char *auth_list);
+Authmethod *authmethod_get(char *authlist);
+Authmethod *authmethod_lookup(const char *name);
Authmethod authmethods[] = {
{"publickey",
@@ -485,6 +491,14 @@ Authmethod authmethods[] = {
userauth_passwd,
&options.password_authentication,
&options.batch_mode},
+ {"keyboard-interactive",
+ userauth_kbdint,
+ &options.kbd_interactive_authentication,
+ &options.batch_mode},
+ {"none",
+ userauth_none,
+ NULL,
+ NULL},
{NULL, NULL, NULL, NULL}
};
@@ -521,17 +535,13 @@ ssh_userauth2(const char *server_user, char *host)
authctxt.host = host;
authctxt.service = "ssh-connection"; /* service name */
authctxt.success = 0;
- authctxt.method = NULL;
+ authctxt.method = authmethod_lookup("none");
+ if (authctxt.method == NULL)
+ fatal("ssh_userauth2: internal error: cannot send userauth none request");
+ authmethod_clear();
/* initial userauth request */
- packet_start(SSH2_MSG_USERAUTH_REQUEST);
- packet_put_cstring(authctxt.server_user);
- packet_put_cstring(authctxt.service);
- packet_put_cstring("none");
- packet_send();
- packet_write_wait();
-
- authmethod_clear();
+ userauth_none(&authctxt);
dispatch_init(&input_userauth_error);
dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
@@ -541,7 +551,7 @@ ssh_userauth2(const char *server_user, char *host)
if (authctxt.agent != NULL)
ssh_close_authentication_connection(authctxt.agent);
- debug("ssh-userauth2 successfull");
+ debug("ssh-userauth2 successfull: method %s", authctxt.method->name);
}
void
input_userauth_error(int type, int plen, void *ctxt)
@@ -563,12 +573,11 @@ input_userauth_failure(int type, int plen, void *ctxt)
Authctxt *authctxt = ctxt;
char *authlist = NULL;
int partial;
- int dlen;
if (authctxt == NULL)
fatal("input_userauth_failure: no authentication context");
- authlist = packet_get_string(&dlen);
+ authlist = packet_get_string(NULL);
partial = packet_get_char();
packet_done();
@@ -577,12 +586,12 @@ input_userauth_failure(int type, int plen, void *ctxt)
debug("authentications that can continue: %s", authlist);
for (;;) {
- /* try old method or get next method */
method = authmethod_get(authlist);
if (method == NULL)
fatal("Unable to find an authentication method");
+ authctxt->method = method;
if (method->userauth(authctxt) != 0) {
- debug2("we sent a packet, wait for reply");
+ debug2("we sent a %s packet, wait for reply", method->name);
break;
} else {
debug2("we did not send a packet, disable method");
@@ -593,6 +602,19 @@ input_userauth_failure(int type, int plen, void *ctxt)
}
int
+userauth_none(Authctxt *authctxt)
+{
+ /* initial userauth request */
+ packet_start(SSH2_MSG_USERAUTH_REQUEST);
+ packet_put_cstring(authctxt->server_user);
+ packet_put_cstring(authctxt->service);
+ packet_put_cstring(authctxt->method->name);
+ packet_send();
+ packet_write_wait();
+ return 1;
+}
+
+int
userauth_passwd(Authctxt *authctxt)
{
static int attempt = 0;
@@ -611,7 +633,7 @@ userauth_passwd(Authctxt *authctxt)
packet_start(SSH2_MSG_USERAUTH_REQUEST);
packet_put_cstring(authctxt->server_user);
packet_put_cstring(authctxt->service);
- packet_put_cstring("password");
+ packet_put_cstring(authctxt->method->name);
packet_put_char(0);
packet_put_cstring(password);
memset(password, 0, strlen(password));
@@ -629,6 +651,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
int bloblen, slen;
int skip = 0;
int ret = -1;
+ int have_sig = 1;
dsa_make_key_blob(k, &blob, &bloblen);
@@ -647,8 +670,8 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
datafellows & SSH_BUG_PUBKEYAUTH ?
"ssh-userauth" :
authctxt->service);
- buffer_put_cstring(&b, "publickey");
- buffer_put_char(&b, 1);
+ buffer_put_cstring(&b, authctxt->method->name);
+ buffer_put_char(&b, have_sig);
buffer_put_cstring(&b, KEX_DSS);
buffer_put_string(&b, blob, bloblen);
@@ -668,8 +691,8 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
buffer_put_cstring(&b, authctxt->server_user);
buffer_put_cstring(&b, authctxt->service);
- buffer_put_cstring(&b, "publickey");
- buffer_put_char(&b, 1);
+ buffer_put_cstring(&b, authctxt->method->name);
+ buffer_put_char(&b, have_sig);
buffer_put_cstring(&b, KEX_DSS);
buffer_put_string(&b, blob, bloblen);
}
@@ -793,6 +816,92 @@ userauth_pubkey(Authctxt *authctxt)
return sent;
}
+/*
+ * Send userauth request message specifying keyboard-interactive method.
+ */
+int
+userauth_kbdint(Authctxt *authctxt)
+{
+ static int attempt = 0;
+
+ if (attempt++ >= options.number_of_password_prompts)
+ return 0;
+
+ debug2("userauth_kbdint");
+ packet_start(SSH2_MSG_USERAUTH_REQUEST);
+ packet_put_cstring(authctxt->server_user);
+ packet_put_cstring(authctxt->service);
+ packet_put_cstring(authctxt->method->name);
+ packet_put_cstring(""); /* lang */
+ packet_put_cstring(options.kbd_interactive_devices ?
+ options.kbd_interactive_devices : "");
+ packet_send();
+ packet_write_wait();
+
+ dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req);
+ return 1;
+}
+
+/*
+ * parse SSH2_MSG_USERAUTH_INFO_REQUEST, prompt user and send
+ * SSH2_MSG_USERAUTH_INFO_RESPONSE
+ */
+void
+input_userauth_info_req(int type, int plen, void *ctxt)
+{
+ Authctxt *authctxt = ctxt;
+ char *name = NULL;
+ char *inst = NULL;
+ char *lang = NULL;
+ char *prompt = NULL;
+ char *response = NULL;
+ unsigned int num_prompts, i;
+ int echo = 0;
+
+ debug2("input_userauth_info_req");
+
+ if (authctxt == NULL)
+ fatal("input_userauth_info_req: no authentication context");
+
+ name = packet_get_string(NULL);
+ inst = packet_get_string(NULL);
+ lang = packet_get_string(NULL);
+
+ if (strlen(name) > 0)
+ cli_mesg(name);
+ xfree(name);
+
+ if (strlen(inst) > 0)
+ cli_mesg(inst);
+ xfree(inst);
+ xfree(lang); /* unused */
+
+ num_prompts = packet_get_int();
+ /*
+ * Begin to build info response packet based on prompts requested.
+ * We commit to providing the correct number of responses, so if
+ * further on we run into a problem that prevents this, we have to
+ * be sure and clean this up and send a correct error response.
+ */
+ packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
+ packet_put_int(num_prompts);
+
+ for (i = 0; i < num_prompts; i++) {
+ prompt = packet_get_string(NULL);
+ echo = packet_get_char();
+
+ response = cli_prompt(prompt, echo);
+
+ packet_put_cstring(response);
+ memset(response, 0, strlen(response));
+ xfree(response);
+ xfree(prompt);
+ }
+ packet_done(); /* done with parsing incoming message. */
+
+ packet_send();
+ packet_write_wait();
+}
/* find auth method */
@@ -879,6 +988,7 @@ authmethod_get(char *authlist)
if (authlist_current == NULL || strcmp(authlist, authlist_current) != 0) {
/* start over if passed a different list */
+ debug3("start over, passed a different list");
authmethod_clear();
authlist_current = xstrdup(authlist);
authlist_working = xstrdup(authlist);
@@ -893,16 +1003,20 @@ authmethod_get(char *authlist)
}
while (name != NULL) {
+ debug3("authmethod_lookup %s", name);
method = authmethod_lookup(name);
- if (method != NULL && authmethod_is_enabled(method))
+ if (method != NULL && authmethod_is_enabled(method)) {
+ debug3("authmethod_is_enabled %s", name);
break;
+ }
name = strtok_r(NULL, DELIM, &authlist_state);
+ method = NULL;
}
if (authname_current != NULL)
xfree(authname_current);
- if (name != NULL) {
+ if (method != NULL) {
debug("next auth method to try is %s", name);
authname_current = xstrdup(name);
return method;
diff --git a/usr.bin/ssh/sshd/Makefile b/usr.bin/ssh/sshd/Makefile
index 4938d58744d..0a9fba8e052 100644
--- a/usr.bin/ssh/sshd/Makefile
+++ b/usr.bin/ssh/sshd/Makefile
@@ -26,7 +26,7 @@ DPADD+= ${LIBKRB}
.endif # KERBEROS
.if (${SKEY:L} == "yes")
-SRCS+= auth-skey.c
+SRCS+= auth-skey.c auth2-skey.c
.endif
.include <bsd.prog.mk>
diff --git a/usr.bin/ssh/sshd_config b/usr.bin/ssh/sshd_config
index 71e73ba9dc0..0ef2fa8915b 100644
--- a/usr.bin/ssh/sshd_config
+++ b/usr.bin/ssh/sshd_config
@@ -37,6 +37,7 @@ PasswordAuthentication yes
PermitEmptyPasswords no
# Uncomment to disable s/key passwords
#SkeyAuthentication no
+#KbdInteractiveAuthentication yes
# To change Kerberos options
#KerberosAuthentication no