summaryrefslogtreecommitdiff
path: root/usr.bin/ssh/auth2-chall.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/ssh/auth2-chall.c')
-rw-r--r--usr.bin/ssh/auth2-chall.c279
1 files changed, 237 insertions, 42 deletions
diff --git a/usr.bin/ssh/auth2-chall.c b/usr.bin/ssh/auth2-chall.c
index 5af60e42fa0..ad4f7ac42e5 100644
--- a/usr.bin/ssh/auth2-chall.c
+++ b/usr.bin/ssh/auth2-chall.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
+ * Copyright (c) 2001 Per Allansson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -22,91 +23,285 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
-RCSID("$OpenBSD: auth2-chall.c,v 1.4 2001/03/28 22:43:31 markus Exp $");
+RCSID("$OpenBSD: auth2-chall.c,v 1.5 2001/05/18 14:13:28 markus Exp $");
#include "ssh2.h"
#include "auth.h"
#include "packet.h"
#include "xmalloc.h"
#include "dispatch.h"
+#include "auth.h"
#include "log.h"
-void send_userauth_into_request(Authctxt *authctxt, char *challenge, int echo);
-void input_userauth_info_response(int type, int plen, void *ctxt);
+static int auth2_challenge_start(Authctxt *authctxt);
+static int send_userauth_info_request(Authctxt *authctxt);
+static void input_userauth_info_response(int type, int plen, void *ctxt);
+
+#ifdef BSD_AUTH
+extern KbdintDevice bsdauth_device;
+#else
+#ifdef SKEY
+extern KbdintDevice skey_device;
+#endif
+#endif
+
+KbdintDevice *devices[] = {
+#ifdef BSD_AUTH
+ &bsdauth_device,
+#else
+#ifdef SKEY
+ &skey_device,
+#endif
+#endif
+ NULL
+};
+
+typedef struct KbdintAuthctxt KbdintAuthctxt;
+struct KbdintAuthctxt
+{
+ char *devices;
+ void *ctxt;
+ KbdintDevice *device;
+};
+
+KbdintAuthctxt *
+kbdint_alloc(const char *devs)
+{
+ KbdintAuthctxt *kbdintctxt;
+ int i;
+ char buf[1024];
+
+ kbdintctxt = xmalloc(sizeof(KbdintAuthctxt));
+ if (strcmp(devs, "") == 0) {
+ buf[0] = '\0';
+ for (i = 0; devices[i]; i++) {
+ if (i != 0)
+ strlcat(buf, ",", sizeof(buf));
+ strlcat(buf, devices[i]->name, sizeof(buf));
+ }
+ debug("kbdint_alloc: devices '%s'", buf);
+ kbdintctxt->devices = xstrdup(buf);
+ } else {
+ kbdintctxt->devices = xstrdup(devs);
+ }
+ kbdintctxt->ctxt = NULL;
+ kbdintctxt->device = NULL;
+
+ return kbdintctxt;
+}
+void
+kbdint_reset_device(KbdintAuthctxt *kbdintctxt)
+{
+ if (kbdintctxt->ctxt) {
+ kbdintctxt->device->free_ctx(kbdintctxt->ctxt);
+ kbdintctxt->ctxt = NULL;
+ }
+ kbdintctxt->device = NULL;
+}
+void
+kbdint_free(KbdintAuthctxt *kbdintctxt)
+{
+ if (kbdintctxt->device)
+ kbdint_reset_device(kbdintctxt);
+ if (kbdintctxt->devices) {
+ xfree(kbdintctxt->devices);
+ kbdintctxt->devices = NULL;
+ }
+ xfree(kbdintctxt);
+}
+/* get next device */
+int
+kbdint_next_device(KbdintAuthctxt *kbdintctxt)
+{
+ size_t len;
+ char *t;
+ int i;
+
+ if (kbdintctxt->device)
+ kbdint_reset_device(kbdintctxt);
+ do {
+ len = kbdintctxt->devices ?
+ strcspn(kbdintctxt->devices, ",") : 0;
+
+ if (len == 0)
+ break;
+ for (i = 0; devices[i]; i++)
+ if (strncmp(kbdintctxt->devices, devices[i]->name, len) == 0)
+ kbdintctxt->device = devices[i];
+ t = kbdintctxt->devices;
+ kbdintctxt->devices = t[len] ? xstrdup(t+len+1) : NULL;
+ xfree(t);
+ debug2("kbdint_next_device: devices %s", kbdintctxt->devices ?
+ kbdintctxt->devices : "<empty>");
+ } while (kbdintctxt->devices && !kbdintctxt->device);
+
+ return kbdintctxt->device ? 1 : 0;
+}
/*
- * try challenge-reponse, return -1 (= postponed) if we have to
+ * try challenge-reponse, set authctxt->postponed if we have to
* wait for the response.
*/
int
auth2_challenge(Authctxt *authctxt, char *devs)
{
- char *challenge;
+ debug("auth2_challenge: user=%s devs=%s",
+ authctxt->user ? authctxt->user : "<nouser>",
+ devs ? devs : "<no devs>");
+
+ if (!authctxt->valid || authctxt->user == NULL || !devs)
+ return 0;
+ if (authctxt->kbdintctxt == NULL)
+ authctxt->kbdintctxt = kbdint_alloc(devs);
+ return auth2_challenge_start(authctxt);
+}
+
+/* side effect: sets authctxt->postponed if a reply was sent*/
+static int
+auth2_challenge_start(Authctxt *authctxt)
+{
+ KbdintAuthctxt *kbdintctxt = authctxt->kbdintctxt;
+
+ debug2("auth2_challenge_start: devices %s",
+ kbdintctxt->devices ? kbdintctxt->devices : "<empty>");
+
+ if (kbdint_next_device(kbdintctxt) == 0) {
+ kbdint_free(kbdintctxt);
+ authctxt->kbdintctxt = NULL;
+ return 0;
+ }
+ debug("auth2_challenge_start: trying authentication method '%s'",
+ kbdintctxt->device->name);
- if (!authctxt->valid || authctxt->user == NULL)
+ if ((kbdintctxt->ctxt = kbdintctxt->device->init_ctx(authctxt)) == NULL) {
+ kbdint_free(kbdintctxt);
+ authctxt->kbdintctxt = NULL;
return 0;
- if ((challenge = get_challenge(authctxt, devs)) == NULL)
+ }
+ if (send_userauth_info_request(authctxt) == 0) {
+ kbdint_free(kbdintctxt);
+ authctxt->kbdintctxt = NULL;
return 0;
- send_userauth_into_request(authctxt, challenge, 0);
+ }
dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
&input_userauth_info_response);
+
authctxt->postponed = 1;
return 0;
}
-void
-send_userauth_into_request(Authctxt *authctxt, char *challenge, int echo)
+static int
+send_userauth_info_request(Authctxt *authctxt)
{
- int nprompts = 1;
+ KbdintAuthctxt *kbdintctxt;
+ char *name, *instr, **prompts;
+ int i;
+ u_int numprompts, *echo_on;
+
+ kbdintctxt = authctxt->kbdintctxt;
+ if (kbdintctxt->device->query(kbdintctxt->ctxt,
+ &name, &instr, &numprompts, &prompts, &echo_on))
+ return 0;
packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
- /* name, instruction and language are unused */
- packet_put_cstring("");
- packet_put_cstring("");
- packet_put_cstring("");
- packet_put_int(nprompts);
- packet_put_cstring(challenge);
- packet_put_char(echo);
+ packet_put_cstring(name);
+ packet_put_cstring(instr);
+ packet_put_cstring(""); /* language not used */
+ packet_put_int(numprompts);
+ for (i = 0; i < numprompts; i++) {
+ packet_put_cstring(prompts[i]);
+ packet_put_char(echo_on[i]);
+ }
packet_send();
packet_write_wait();
+
+ for (i = 0; i < numprompts; i++)
+ xfree(prompts[i]);
+ xfree(prompts);
+ xfree(echo_on);
+ xfree(name);
+ xfree(instr);
+ return 1;
}
-void
+static void
input_userauth_info_response(int type, int plen, void *ctxt)
{
Authctxt *authctxt = ctxt;
- int authenticated = 0;
- u_int nresp, rlen;
- char *response, *method = "challenge-reponse";
+ KbdintAuthctxt *kbdintctxt;
+ int i, authenticated = 0, res, len;
+ u_int nresp;
+ char **response = NULL, *method;
if (authctxt == NULL)
fatal("input_userauth_info_response: no authctxt");
+ kbdintctxt = authctxt->kbdintctxt;
+ if (kbdintctxt == NULL || kbdintctxt->ctxt == NULL)
+ fatal("input_userauth_info_response: no kbdintctxt");
+ if (kbdintctxt->device == NULL)
+ fatal("input_userauth_info_response: no device");
authctxt->postponed = 0; /* reset */
nresp = packet_get_int();
- if (nresp == 1) {
- response = packet_get_string(&rlen);
- packet_done();
- if (strlen(response) == 0) {
- /*
- * if we received an empty response, resend challenge
- * with echo enabled
- */
- char *challenge = get_challenge(authctxt, NULL);
- if (challenge != NULL) {
- send_userauth_into_request(authctxt,
- challenge, 1);
- authctxt->postponed = 1;
- }
- } else if (authctxt->valid) {
- authenticated = verify_response(authctxt, response);
- memset(response, 'r', rlen);
- }
+ if (nresp > 0) {
+ response = xmalloc(nresp * sizeof(char*));
+ for (i = 0; i < nresp; i++)
+ response[i] = packet_get_string(NULL);
+ }
+ packet_done();
+
+ if (authctxt->valid) {
+ res = kbdintctxt->device->respond(kbdintctxt->ctxt,
+ nresp, response);
+ } else {
+ res = -1;
+ }
+
+ for (i = 0; i < nresp; i++) {
+ memset(response[i], 'r', strlen(response[i]));
+ xfree(response[i]);
+ }
+ if (response)
xfree(response);
+
+ switch (res) {
+ case 0:
+ /* Success! */
+ authenticated = 1;
+ break;
+ case 1:
+ /* Authentication needs further interaction */
+ authctxt->postponed = 1;
+ if (send_userauth_info_request(authctxt) == 0) {
+ authctxt->postponed = 0;
+ }
+ break;
+ default:
+ /* Failure! */
+ break;
}
- /* unregister callback */
- if (!authctxt->postponed)
+
+ len = strlen("keyboard-interactive") + 2 +
+ strlen(kbdintctxt->device->name);
+ method = xmalloc(len);
+ method[0] = '\0';
+ strlcat(method, "keyboard-interactive", len);
+ strlcat(method, "/", len);
+ strlcat(method, kbdintctxt->device->name, len);
+
+ if (!authctxt->postponed) {
+ /* unregister callback */
dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
+ if (authenticated) {
+ kbdint_free(kbdintctxt);
+ authctxt->kbdintctxt = NULL;
+ } else {
+ /* start next device */
+ /* may set authctxt->postponed */
+ auth2_challenge_start(authctxt);
+ }
+ }
userauth_finish(authctxt, authenticated, method);
+ xfree(method);
}