Annotation of src/usr.bin/ssh/auth2-chall.c, Revision 1.49
1.49 ! markus 1: /* $OpenBSD: auth2-chall.c,v 1.48 2017/05/30 14:29:59 markus Exp $ */
1.1 markus 2: /*
1.3 deraadt 3: * Copyright (c) 2001 Markus Friedl. All rights reserved.
1.5 markus 4: * Copyright (c) 2001 Per Allansson. All rights reserved.
1.1 markus 5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25: */
1.30 deraadt 26:
27: #include <sys/types.h>
1.28 stevesk 28:
1.29 stevesk 29: #include <stdio.h>
1.28 stevesk 30: #include <string.h>
1.1 markus 31:
1.30 deraadt 32: #include "xmalloc.h"
1.1 markus 33: #include "ssh2.h"
1.49 ! markus 34: #include "sshkey.h"
1.30 deraadt 35: #include "hostfile.h"
1.1 markus 36: #include "auth.h"
1.49 ! markus 37: #include "sshbuf.h"
1.1 markus 38: #include "packet.h"
39: #include "dispatch.h"
1.49 ! markus 40: #include "ssherr.h"
1.2 markus 41: #include "log.h"
1.1 markus 42:
1.48 markus 43: static int auth2_challenge_start(struct ssh *);
1.49 ! markus 44: static int send_userauth_info_request(struct ssh *);
1.47 markus 45: static int input_userauth_info_response(int, u_int32_t, struct ssh *);
1.5 markus 46:
47: extern KbdintDevice bsdauth_device;
48:
49: KbdintDevice *devices[] = {
50: &bsdauth_device,
51: NULL
52: };
53:
54: typedef struct KbdintAuthctxt KbdintAuthctxt;
55: struct KbdintAuthctxt
56: {
57: char *devices;
58: void *ctxt;
59: KbdintDevice *device;
1.19 markus 60: u_int nreq;
1.43 djm 61: u_int devices_done;
1.5 markus 62: };
63:
1.7 itojun 64: static KbdintAuthctxt *
1.5 markus 65: kbdint_alloc(const char *devs)
66: {
67: KbdintAuthctxt *kbdintctxt;
1.49 ! markus 68: struct sshbuf *b;
! 69: int i, r;
1.5 markus 70:
1.39 djm 71: kbdintctxt = xcalloc(1, sizeof(KbdintAuthctxt));
1.5 markus 72: if (strcmp(devs, "") == 0) {
1.49 ! markus 73: if ((b = sshbuf_new()) == NULL)
! 74: fatal("%s: sshbuf_new failed", __func__);
1.5 markus 75: for (i = 0; devices[i]; i++) {
1.49 ! markus 76: if ((r = sshbuf_putf(b, "%s%s",
! 77: sshbuf_len(b) ? "," : "", devices[i]->name)) != 0)
! 78: fatal("%s: buffer error: %s",
! 79: __func__, ssh_err(r));
1.5 markus 80: }
1.49 ! markus 81: if ((kbdintctxt->devices = sshbuf_dup_string(b)) == NULL)
1.44 djm 82: fatal("%s: sshbuf_dup_string failed", __func__);
1.49 ! markus 83: sshbuf_free(b);
1.5 markus 84: } else {
85: kbdintctxt->devices = xstrdup(devs);
86: }
1.16 markus 87: debug("kbdint_alloc: devices '%s'", kbdintctxt->devices);
1.5 markus 88: kbdintctxt->ctxt = NULL;
89: kbdintctxt->device = NULL;
1.19 markus 90: kbdintctxt->nreq = 0;
1.5 markus 91:
92: return kbdintctxt;
93: }
1.7 itojun 94: static void
1.5 markus 95: kbdint_reset_device(KbdintAuthctxt *kbdintctxt)
96: {
97: if (kbdintctxt->ctxt) {
98: kbdintctxt->device->free_ctx(kbdintctxt->ctxt);
99: kbdintctxt->ctxt = NULL;
100: }
101: kbdintctxt->device = NULL;
102: }
1.7 itojun 103: static void
1.5 markus 104: kbdint_free(KbdintAuthctxt *kbdintctxt)
105: {
106: if (kbdintctxt->device)
107: kbdint_reset_device(kbdintctxt);
1.38 djm 108: free(kbdintctxt->devices);
1.40 tedu 109: explicit_bzero(kbdintctxt, sizeof(*kbdintctxt));
1.38 djm 110: free(kbdintctxt);
1.5 markus 111: }
112: /* get next device */
1.7 itojun 113: static int
1.37 markus 114: kbdint_next_device(Authctxt *authctxt, KbdintAuthctxt *kbdintctxt)
1.5 markus 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;
1.37 markus 128: for (i = 0; devices[i]; i++) {
1.43 djm 129: if ((kbdintctxt->devices_done & (1 << i)) != 0 ||
130: !auth2_method_allowed(authctxt,
1.37 markus 131: "keyboard-interactive", devices[i]->name))
132: continue;
1.43 djm 133: if (strncmp(kbdintctxt->devices, devices[i]->name,
134: len) == 0) {
1.5 markus 135: kbdintctxt->device = devices[i];
1.43 djm 136: kbdintctxt->devices_done |= 1 << i;
137: }
1.37 markus 138: }
1.5 markus 139: t = kbdintctxt->devices;
140: kbdintctxt->devices = t[len] ? xstrdup(t+len+1) : NULL;
1.38 djm 141: free(t);
1.5 markus 142: debug2("kbdint_next_device: devices %s", kbdintctxt->devices ?
1.24 djm 143: kbdintctxt->devices : "<empty>");
1.5 markus 144: } while (kbdintctxt->devices && !kbdintctxt->device);
145:
146: return kbdintctxt->device ? 1 : 0;
147: }
1.1 markus 148:
149: /*
1.8 markus 150: * try challenge-response, set authctxt->postponed if we have to
1.1 markus 151: * wait for the response.
152: */
153: int
1.48 markus 154: auth2_challenge(struct ssh *ssh, char *devs)
1.1 markus 155: {
1.48 markus 156: Authctxt *authctxt = ssh->authctxt;
1.5 markus 157: debug("auth2_challenge: user=%s devs=%s",
158: authctxt->user ? authctxt->user : "<nouser>",
159: devs ? devs : "<no devs>");
160:
1.6 markus 161: if (authctxt->user == NULL || !devs)
1.5 markus 162: return 0;
1.10 deraadt 163: if (authctxt->kbdintctxt == NULL)
1.5 markus 164: authctxt->kbdintctxt = kbdint_alloc(devs);
1.48 markus 165: return auth2_challenge_start(ssh);
1.5 markus 166: }
167:
1.9 markus 168: /* unregister kbd-int callbacks and context */
169: void
1.48 markus 170: auth2_challenge_stop(struct ssh *ssh)
1.9 markus 171: {
1.48 markus 172: Authctxt *authctxt = ssh->authctxt;
1.9 markus 173: /* unregister callback */
1.48 markus 174: ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
1.32 stevesk 175: if (authctxt->kbdintctxt != NULL) {
1.9 markus 176: kbdint_free(authctxt->kbdintctxt);
177: authctxt->kbdintctxt = NULL;
178: }
179: }
180:
1.5 markus 181: /* side effect: sets authctxt->postponed if a reply was sent*/
182: static int
1.48 markus 183: auth2_challenge_start(struct ssh *ssh)
1.5 markus 184: {
1.48 markus 185: Authctxt *authctxt = ssh->authctxt;
1.5 markus 186: KbdintAuthctxt *kbdintctxt = authctxt->kbdintctxt;
187:
188: debug2("auth2_challenge_start: devices %s",
189: kbdintctxt->devices ? kbdintctxt->devices : "<empty>");
190:
1.37 markus 191: if (kbdint_next_device(authctxt, kbdintctxt) == 0) {
1.48 markus 192: auth2_challenge_stop(ssh);
1.5 markus 193: return 0;
194: }
195: debug("auth2_challenge_start: trying authentication method '%s'",
196: kbdintctxt->device->name);
1.1 markus 197:
1.5 markus 198: if ((kbdintctxt->ctxt = kbdintctxt->device->init_ctx(authctxt)) == NULL) {
1.48 markus 199: auth2_challenge_stop(ssh);
1.1 markus 200: return 0;
1.5 markus 201: }
1.49 ! markus 202: if (send_userauth_info_request(ssh) == 0) {
1.48 markus 203: auth2_challenge_stop(ssh);
1.1 markus 204: return 0;
1.5 markus 205: }
1.48 markus 206: ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_INFO_RESPONSE,
1.1 markus 207: &input_userauth_info_response);
1.5 markus 208:
1.1 markus 209: authctxt->postponed = 1;
210: return 0;
211: }
212:
1.5 markus 213: static int
1.49 ! markus 214: send_userauth_info_request(struct ssh *ssh)
1.1 markus 215: {
1.49 ! markus 216: Authctxt *authctxt = ssh->authctxt;
1.5 markus 217: KbdintAuthctxt *kbdintctxt;
218: char *name, *instr, **prompts;
1.49 ! markus 219: u_int r, i, *echo_on;
1.5 markus 220:
221: kbdintctxt = authctxt->kbdintctxt;
222: if (kbdintctxt->device->query(kbdintctxt->ctxt,
1.19 markus 223: &name, &instr, &kbdintctxt->nreq, &prompts, &echo_on))
1.5 markus 224: return 0;
1.1 markus 225:
1.49 ! markus 226: if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_INFO_REQUEST)) != 0 ||
! 227: (r = sshpkt_put_cstring(ssh, name)) != 0 ||
! 228: (r = sshpkt_put_cstring(ssh, instr)) != 0 ||
! 229: (r = sshpkt_put_cstring(ssh, "")) != 0 || /* language not used */
! 230: (r = sshpkt_put_u32(ssh, kbdintctxt->nreq)) != 0)
! 231: fatal("%s: %s", __func__, ssh_err(r));
1.19 markus 232: for (i = 0; i < kbdintctxt->nreq; i++) {
1.49 ! markus 233: if ((r = sshpkt_put_cstring(ssh, prompts[i])) != 0 ||
! 234: (r = sshpkt_put_u8(ssh, echo_on[i])) != 0)
! 235: fatal("%s: %s", __func__, ssh_err(r));
1.5 markus 236: }
1.49 ! markus 237: if ((r = sshpkt_send(ssh)) != 0)
! 238: fatal("%s: %s", __func__, ssh_err(r));
! 239: ssh_packet_write_wait(ssh);
1.5 markus 240:
1.19 markus 241: for (i = 0; i < kbdintctxt->nreq; i++)
1.38 djm 242: free(prompts[i]);
243: free(prompts);
244: free(echo_on);
245: free(name);
246: free(instr);
1.5 markus 247: return 1;
1.1 markus 248: }
249:
1.42 markus 250: static int
1.47 markus 251: input_userauth_info_response(int type, u_int32_t seq, struct ssh *ssh)
1.1 markus 252: {
1.46 markus 253: Authctxt *authctxt = ssh->authctxt;
1.5 markus 254: KbdintAuthctxt *kbdintctxt;
1.34 djm 255: int authenticated = 0, res;
1.49 ! markus 256: int r;
1.23 djm 257: u_int i, nresp;
1.36 djm 258: const char *devicename = NULL;
259: char **response = NULL;
1.1 markus 260:
261: if (authctxt == NULL)
262: fatal("input_userauth_info_response: no authctxt");
1.5 markus 263: kbdintctxt = authctxt->kbdintctxt;
264: if (kbdintctxt == NULL || kbdintctxt->ctxt == NULL)
265: fatal("input_userauth_info_response: no kbdintctxt");
266: if (kbdintctxt->device == NULL)
267: fatal("input_userauth_info_response: no device");
1.1 markus 268:
269: authctxt->postponed = 0; /* reset */
1.49 ! markus 270: if ((r = sshpkt_get_u32(ssh, &nresp)) != 0)
! 271: fatal("%s: %s", __func__, ssh_err(r));
1.19 markus 272: if (nresp != kbdintctxt->nreq)
273: fatal("input_userauth_info_response: wrong number of replies");
274: if (nresp > 100)
275: fatal("input_userauth_info_response: too many replies");
1.5 markus 276: if (nresp > 0) {
1.26 djm 277: response = xcalloc(nresp, sizeof(char *));
1.5 markus 278: for (i = 0; i < nresp; i++)
1.49 ! markus 279: if ((r = sshpkt_get_cstring(ssh, &response[i],
! 280: NULL)) != 0)
! 281: fatal("%s: %s", __func__, ssh_err(r));
1.5 markus 282: }
1.49 ! markus 283: if ((r = sshpkt_get_end(ssh)) != 0)
! 284: fatal("%s: %s", __func__, ssh_err(r));
1.5 markus 285:
1.22 dtucker 286: res = kbdintctxt->device->respond(kbdintctxt->ctxt, nresp, response);
1.5 markus 287:
288: for (i = 0; i < nresp; i++) {
1.41 djm 289: explicit_bzero(response[i], strlen(response[i]));
1.38 djm 290: free(response[i]);
1.5 markus 291: }
1.38 djm 292: free(response);
1.5 markus 293:
294: switch (res) {
295: case 0:
296: /* Success! */
1.22 dtucker 297: authenticated = authctxt->valid ? 1 : 0;
1.5 markus 298: break;
299: case 1:
300: /* Authentication needs further interaction */
1.49 ! markus 301: if (send_userauth_info_request(ssh) == 1)
1.9 markus 302: authctxt->postponed = 1;
1.5 markus 303: break;
304: default:
305: /* Failure! */
306: break;
1.1 markus 307: }
1.35 djm 308: devicename = kbdintctxt->device->name;
1.5 markus 309: if (!authctxt->postponed) {
310: if (authenticated) {
1.48 markus 311: auth2_challenge_stop(ssh);
1.5 markus 312: } else {
313: /* start next device */
314: /* may set authctxt->postponed */
1.48 markus 315: auth2_challenge_start(ssh);
1.5 markus 316: }
317: }
1.48 markus 318: userauth_finish(ssh, authenticated, "keyboard-interactive",
1.35 djm 319: devicename);
1.42 markus 320: return 0;
1.17 provos 321: }
322:
323: void
324: privsep_challenge_enable(void)
325: {
326: extern KbdintDevice mm_bsdauth_device;
327: devices[0] = &mm_bsdauth_device;
1.1 markus 328: }