Annotation of src/usr.bin/ssh/auth2-chall.c, Revision 1.2.2.5
1.1 markus 1: /*
1.2.2.3 jason 2: * Copyright (c) 2001 Markus Friedl. All rights reserved.
1.2.2.5 ! miod 3: * Copyright (c) 2001 Per Allansson. All rights reserved.
1.1 markus 4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: *
14: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24: */
25: #include "includes.h"
1.2.2.5 ! miod 26: RCSID("$OpenBSD: auth2-chall.c,v 1.7 2001/06/23 15:12:17 itojun Exp $");
1.1 markus 27:
28: #include "ssh2.h"
29: #include "auth.h"
30: #include "packet.h"
31: #include "xmalloc.h"
32: #include "dispatch.h"
1.2.2.5 ! miod 33: #include "auth.h"
1.2 markus 34: #include "log.h"
1.1 markus 35:
1.2.2.5 ! miod 36: static int auth2_challenge_start(Authctxt *);
! 37: static int send_userauth_info_request(Authctxt *);
! 38: static void input_userauth_info_response(int, int, void *);
! 39:
! 40: #ifdef BSD_AUTH
! 41: extern KbdintDevice bsdauth_device;
! 42: #else
! 43: #ifdef SKEY
! 44: extern KbdintDevice skey_device;
! 45: #endif
! 46: #endif
! 47:
! 48: KbdintDevice *devices[] = {
! 49: #ifdef BSD_AUTH
! 50: &bsdauth_device,
! 51: #else
! 52: #ifdef SKEY
! 53: &skey_device,
! 54: #endif
! 55: #endif
! 56: NULL
! 57: };
! 58:
! 59: typedef struct KbdintAuthctxt KbdintAuthctxt;
! 60: struct KbdintAuthctxt
! 61: {
! 62: char *devices;
! 63: void *ctxt;
! 64: KbdintDevice *device;
! 65: };
! 66:
! 67: static KbdintAuthctxt *
! 68: kbdint_alloc(const char *devs)
! 69: {
! 70: KbdintAuthctxt *kbdintctxt;
! 71: int i;
! 72: char buf[1024];
! 73:
! 74: kbdintctxt = xmalloc(sizeof(KbdintAuthctxt));
! 75: if (strcmp(devs, "") == 0) {
! 76: buf[0] = '\0';
! 77: for (i = 0; devices[i]; i++) {
! 78: if (i != 0)
! 79: strlcat(buf, ",", sizeof(buf));
! 80: strlcat(buf, devices[i]->name, sizeof(buf));
! 81: }
! 82: debug("kbdint_alloc: devices '%s'", buf);
! 83: kbdintctxt->devices = xstrdup(buf);
! 84: } else {
! 85: kbdintctxt->devices = xstrdup(devs);
! 86: }
! 87: kbdintctxt->ctxt = NULL;
! 88: kbdintctxt->device = NULL;
! 89:
! 90: return kbdintctxt;
! 91: }
! 92: static void
! 93: kbdint_reset_device(KbdintAuthctxt *kbdintctxt)
! 94: {
! 95: if (kbdintctxt->ctxt) {
! 96: kbdintctxt->device->free_ctx(kbdintctxt->ctxt);
! 97: kbdintctxt->ctxt = NULL;
! 98: }
! 99: kbdintctxt->device = NULL;
! 100: }
! 101: static void
! 102: kbdint_free(KbdintAuthctxt *kbdintctxt)
! 103: {
! 104: if (kbdintctxt->device)
! 105: kbdint_reset_device(kbdintctxt);
! 106: if (kbdintctxt->devices) {
! 107: xfree(kbdintctxt->devices);
! 108: kbdintctxt->devices = NULL;
! 109: }
! 110: xfree(kbdintctxt);
! 111: }
! 112: /* get next device */
! 113: static int
! 114: kbdint_next_device(KbdintAuthctxt *kbdintctxt)
! 115: {
! 116: size_t len;
! 117: char *t;
! 118: int i;
! 119:
! 120: if (kbdintctxt->device)
! 121: kbdint_reset_device(kbdintctxt);
! 122: do {
! 123: len = kbdintctxt->devices ?
! 124: strcspn(kbdintctxt->devices, ",") : 0;
! 125:
! 126: if (len == 0)
! 127: break;
! 128: for (i = 0; devices[i]; i++)
! 129: if (strncmp(kbdintctxt->devices, devices[i]->name, len) == 0)
! 130: kbdintctxt->device = devices[i];
! 131: t = kbdintctxt->devices;
! 132: kbdintctxt->devices = t[len] ? xstrdup(t+len+1) : NULL;
! 133: xfree(t);
! 134: debug2("kbdint_next_device: devices %s", kbdintctxt->devices ?
! 135: kbdintctxt->devices : "<empty>");
! 136: } while (kbdintctxt->devices && !kbdintctxt->device);
! 137:
! 138: return kbdintctxt->device ? 1 : 0;
! 139: }
1.1 markus 140:
141: /*
1.2.2.5 ! miod 142: * try challenge-reponse, set authctxt->postponed if we have to
1.1 markus 143: * wait for the response.
144: */
145: int
146: auth2_challenge(Authctxt *authctxt, char *devs)
147: {
1.2.2.5 ! miod 148: debug("auth2_challenge: user=%s devs=%s",
! 149: authctxt->user ? authctxt->user : "<nouser>",
! 150: devs ? devs : "<no devs>");
1.1 markus 151:
1.2.2.5 ! miod 152: if (authctxt->user == NULL || !devs)
1.1 markus 153: return 0;
1.2.2.5 ! miod 154: if (authctxt->kbdintctxt == NULL)
! 155: authctxt->kbdintctxt = kbdint_alloc(devs);
! 156: return auth2_challenge_start(authctxt);
! 157: }
! 158:
! 159: /* side effect: sets authctxt->postponed if a reply was sent*/
! 160: static int
! 161: auth2_challenge_start(Authctxt *authctxt)
! 162: {
! 163: KbdintAuthctxt *kbdintctxt = authctxt->kbdintctxt;
! 164:
! 165: debug2("auth2_challenge_start: devices %s",
! 166: kbdintctxt->devices ? kbdintctxt->devices : "<empty>");
! 167:
! 168: if (kbdint_next_device(kbdintctxt) == 0) {
! 169: kbdint_free(kbdintctxt);
! 170: authctxt->kbdintctxt = NULL;
! 171: return 0;
! 172: }
! 173: debug("auth2_challenge_start: trying authentication method '%s'",
! 174: kbdintctxt->device->name);
! 175:
! 176: if ((kbdintctxt->ctxt = kbdintctxt->device->init_ctx(authctxt)) == NULL) {
! 177: kbdint_free(kbdintctxt);
! 178: authctxt->kbdintctxt = NULL;
! 179: return 0;
! 180: }
! 181: if (send_userauth_info_request(authctxt) == 0) {
! 182: kbdint_free(kbdintctxt);
! 183: authctxt->kbdintctxt = NULL;
1.1 markus 184: return 0;
1.2.2.5 ! miod 185: }
1.1 markus 186: dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
187: &input_userauth_info_response);
1.2.2.5 ! miod 188:
1.1 markus 189: authctxt->postponed = 1;
190: return 0;
191: }
192:
1.2.2.5 ! miod 193: static int
! 194: send_userauth_info_request(Authctxt *authctxt)
1.1 markus 195: {
1.2.2.5 ! miod 196: KbdintAuthctxt *kbdintctxt;
! 197: char *name, *instr, **prompts;
! 198: int i;
! 199: u_int numprompts, *echo_on;
! 200:
! 201: kbdintctxt = authctxt->kbdintctxt;
! 202: if (kbdintctxt->device->query(kbdintctxt->ctxt,
! 203: &name, &instr, &numprompts, &prompts, &echo_on))
! 204: return 0;
1.1 markus 205:
206: packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
1.2.2.5 ! miod 207: packet_put_cstring(name);
! 208: packet_put_cstring(instr);
! 209: packet_put_cstring(""); /* language not used */
! 210: packet_put_int(numprompts);
! 211: for (i = 0; i < numprompts; i++) {
! 212: packet_put_cstring(prompts[i]);
! 213: packet_put_char(echo_on[i]);
! 214: }
1.1 markus 215: packet_send();
216: packet_write_wait();
1.2.2.5 ! miod 217:
! 218: for (i = 0; i < numprompts; i++)
! 219: xfree(prompts[i]);
! 220: xfree(prompts);
! 221: xfree(echo_on);
! 222: xfree(name);
! 223: xfree(instr);
! 224: return 1;
1.1 markus 225: }
226:
1.2.2.5 ! miod 227: static void
1.1 markus 228: input_userauth_info_response(int type, int plen, void *ctxt)
229: {
230: Authctxt *authctxt = ctxt;
1.2.2.5 ! miod 231: KbdintAuthctxt *kbdintctxt;
! 232: int i, authenticated = 0, res, len;
! 233: u_int nresp;
! 234: char **response = NULL, *method;
1.1 markus 235:
236: if (authctxt == NULL)
237: fatal("input_userauth_info_response: no authctxt");
1.2.2.5 ! miod 238: kbdintctxt = authctxt->kbdintctxt;
! 239: if (kbdintctxt == NULL || kbdintctxt->ctxt == NULL)
! 240: fatal("input_userauth_info_response: no kbdintctxt");
! 241: if (kbdintctxt->device == NULL)
! 242: fatal("input_userauth_info_response: no device");
1.1 markus 243:
244: authctxt->postponed = 0; /* reset */
245: nresp = packet_get_int();
1.2.2.5 ! miod 246: if (nresp > 0) {
! 247: response = xmalloc(nresp * sizeof(char*));
! 248: for (i = 0; i < nresp; i++)
! 249: response[i] = packet_get_string(NULL);
! 250: }
! 251: packet_done();
! 252:
! 253: if (authctxt->valid) {
! 254: res = kbdintctxt->device->respond(kbdintctxt->ctxt,
! 255: nresp, response);
! 256: } else {
! 257: res = -1;
! 258: }
! 259:
! 260: for (i = 0; i < nresp; i++) {
! 261: memset(response[i], 'r', strlen(response[i]));
! 262: xfree(response[i]);
! 263: }
! 264: if (response)
1.1 markus 265: xfree(response);
1.2.2.5 ! miod 266:
! 267: switch (res) {
! 268: case 0:
! 269: /* Success! */
! 270: authenticated = 1;
! 271: break;
! 272: case 1:
! 273: /* Authentication needs further interaction */
! 274: authctxt->postponed = 1;
! 275: if (send_userauth_info_request(authctxt) == 0) {
! 276: authctxt->postponed = 0;
! 277: }
! 278: break;
! 279: default:
! 280: /* Failure! */
! 281: break;
1.1 markus 282: }
1.2.2.5 ! miod 283:
! 284: len = strlen("keyboard-interactive") + 2 +
! 285: strlen(kbdintctxt->device->name);
! 286: method = xmalloc(len);
! 287: method[0] = '\0';
! 288: strlcat(method, "keyboard-interactive", len);
! 289: strlcat(method, "/", len);
! 290: strlcat(method, kbdintctxt->device->name, len);
! 291:
! 292: if (!authctxt->postponed) {
! 293: /* unregister callback */
1.1 markus 294: dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
1.2.2.4 jason 295:
1.2.2.5 ! miod 296: if (authenticated) {
! 297: kbdint_free(kbdintctxt);
! 298: authctxt->kbdintctxt = NULL;
! 299: } else {
! 300: /* start next device */
! 301: /* may set authctxt->postponed */
! 302: auth2_challenge_start(authctxt);
! 303: }
! 304: }
1.2.2.4 jason 305: userauth_finish(authctxt, authenticated, method);
1.2.2.5 ! miod 306: xfree(method);
1.1 markus 307: }