auth2-chall.c revision 99052
167754Smsmith/* 267754Smsmith * Copyright (c) 2001 Markus Friedl. All rights reserved. 367754Smsmith * Copyright (c) 2001 Per Allansson. All rights reserved. 4128212Snjl * 567754Smsmith * Redistribution and use in source and binary forms, with or without 667754Smsmith * modification, are permitted provided that the following conditions 767754Smsmith * are met: 867754Smsmith * 1. Redistributions of source code must retain the above copyright 967754Smsmith * notice, this list of conditions and the following disclaimer. 1067754Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1167754Smsmith * notice, this list of conditions and the following disclaimer in the 12126372Snjl * documentation and/or other materials provided with the distribution. 1370243Smsmith * 1467754Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1567754Smsmith * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1667754Smsmith * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1767754Smsmith * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1867754Smsmith * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1967754Smsmith * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2067754Smsmith * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2167754Smsmith * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2267754Smsmith * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2367754Smsmith * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2467754Smsmith */ 2567754Smsmith#include "includes.h" 2667754SmsmithRCSID("$OpenBSD: auth2-chall.c,v 1.18 2002/06/19 00:27:55 deraadt Exp $"); 2767754SmsmithRCSID("$FreeBSD: head/crypto/openssh/auth2-chall.c 99052 2002-06-29 10:56:23Z des $"); 2867754Smsmith 2967754Smsmith#include "ssh2.h" 3067754Smsmith#include "auth.h" 3167754Smsmith#include "buffer.h" 3267754Smsmith#include "packet.h" 3367754Smsmith#include "xmalloc.h" 3467754Smsmith#include "dispatch.h" 3567754Smsmith#include "auth.h" 3667754Smsmith#include "log.h" 3767754Smsmith 3867754Smsmithstatic int auth2_challenge_start(Authctxt *); 3967754Smsmithstatic int send_userauth_info_request(Authctxt *); 4067754Smsmithstatic void input_userauth_info_response(int, u_int32_t, void *); 4167754Smsmith 4267754Smsmith#ifdef BSD_AUTH 4367754Smsmithextern KbdintDevice bsdauth_device; 4467754Smsmith#else 4567754Smsmith#ifdef USE_PAM 4667754Smsmithextern KbdintDevice pam_device; 4767754Smsmith#endif 4867754Smsmith#ifdef SKEY 4967754Smsmithextern KbdintDevice skey_device; 5067754Smsmith#endif 5167754Smsmith#endif 5267754Smsmith 5367754SmsmithKbdintDevice *devices[] = { 5467754Smsmith#ifdef BSD_AUTH 5567754Smsmith &bsdauth_device, 5667754Smsmith#else 5767754Smsmith#ifdef USE_PAM 5867754Smsmith &pam_device, 5967754Smsmith#endif 6067754Smsmith#ifdef SKEY 6167754Smsmith &skey_device, 6267754Smsmith#endif 6367754Smsmith#endif 6467754Smsmith NULL 6567754Smsmith}; 6667754Smsmith 6767754Smsmithtypedef struct KbdintAuthctxt KbdintAuthctxt; 6867754Smsmithstruct KbdintAuthctxt 6967754Smsmith{ 7067754Smsmith char *devices; 7167754Smsmith void *ctxt; 7267754Smsmith KbdintDevice *device; 7367754Smsmith}; 7467754Smsmith 7567754Smsmithstatic KbdintAuthctxt * 7667754Smsmithkbdint_alloc(const char *devs) 7767754Smsmith{ 7867754Smsmith KbdintAuthctxt *kbdintctxt; 7967754Smsmith Buffer b; 8067754Smsmith int i; 8167754Smsmith 8267754Smsmith kbdintctxt = xmalloc(sizeof(KbdintAuthctxt)); 8367754Smsmith if (strcmp(devs, "") == 0) { 8467754Smsmith buffer_init(&b); 8567754Smsmith for (i = 0; devices[i]; i++) { 8667754Smsmith if (buffer_len(&b) > 0) 8767754Smsmith buffer_append(&b, ",", 1); 8867754Smsmith buffer_append(&b, devices[i]->name, 8967754Smsmith strlen(devices[i]->name)); 9067754Smsmith } 9167754Smsmith buffer_append(&b, "\0", 1); 9267754Smsmith kbdintctxt->devices = xstrdup(buffer_ptr(&b)); 9367754Smsmith buffer_free(&b); 9467754Smsmith } else { 9567754Smsmith kbdintctxt->devices = xstrdup(devs); 9667754Smsmith } 9767754Smsmith debug("kbdint_alloc: devices '%s'", kbdintctxt->devices); 9867754Smsmith kbdintctxt->ctxt = NULL; 9967754Smsmith kbdintctxt->device = NULL; 10067754Smsmith 10167754Smsmith return kbdintctxt; 10267754Smsmith} 10367754Smsmithstatic void 10467754Smsmithkbdint_reset_device(KbdintAuthctxt *kbdintctxt) 10567754Smsmith{ 10667754Smsmith if (kbdintctxt->ctxt) { 10767754Smsmith kbdintctxt->device->free_ctx(kbdintctxt->ctxt); 10867754Smsmith kbdintctxt->ctxt = NULL; 10967754Smsmith } 11067754Smsmith kbdintctxt->device = NULL; 11167754Smsmith} 11267754Smsmithstatic void 11367754Smsmithkbdint_free(KbdintAuthctxt *kbdintctxt) 11467754Smsmith{ 11567754Smsmith if (kbdintctxt->device) 11667754Smsmith kbdint_reset_device(kbdintctxt); 11767754Smsmith if (kbdintctxt->devices) { 11867754Smsmith xfree(kbdintctxt->devices); 11967754Smsmith kbdintctxt->devices = NULL; 12067754Smsmith } 12167754Smsmith xfree(kbdintctxt); 12267754Smsmith} 12377424Smsmith/* get next device */ 12491116Smsmithstatic int 12567754Smsmithkbdint_next_device(KbdintAuthctxt *kbdintctxt) 12667754Smsmith{ 12767754Smsmith size_t len; 12867754Smsmith char *t; 12967754Smsmith int i; 13067754Smsmith 13167754Smsmith if (kbdintctxt->device) 132107325Siwasaki kbdint_reset_device(kbdintctxt); 13367754Smsmith do { 13477424Smsmith len = kbdintctxt->devices ? 13567754Smsmith strcspn(kbdintctxt->devices, ",") : 0; 13667754Smsmith 13767754Smsmith if (len == 0) 138114237Snjl break; 139114237Snjl for (i = 0; devices[i]; i++) 140107325Siwasaki if (strncmp(kbdintctxt->devices, devices[i]->name, len) == 0) 14167754Smsmith kbdintctxt->device = devices[i]; 14267754Smsmith t = kbdintctxt->devices; 14367754Smsmith kbdintctxt->devices = t[len] ? xstrdup(t+len+1) : NULL; 14467754Smsmith xfree(t); 14567754Smsmith debug2("kbdint_next_device: devices %s", kbdintctxt->devices ? 14667754Smsmith kbdintctxt->devices : "<empty>"); 14767754Smsmith } while (kbdintctxt->devices && !kbdintctxt->device); 14867754Smsmith 14967754Smsmith return kbdintctxt->device ? 1 : 0; 15067754Smsmith} 15167754Smsmith 15267754Smsmith/* 15367754Smsmith * try challenge-response, set authctxt->postponed if we have to 15467754Smsmith * wait for the response. 15567754Smsmith */ 15667754Smsmithint 15767754Smsmithauth2_challenge(Authctxt *authctxt, char *devs) 15891116Smsmith{ 15967754Smsmith debug("auth2_challenge: user=%s devs=%s", 16067754Smsmith authctxt->user ? authctxt->user : "<nouser>", 16167754Smsmith devs ? devs : "<no devs>"); 16267754Smsmith 16367754Smsmith if (authctxt->user == NULL || !devs) 16491116Smsmith return 0; 16567754Smsmith if (authctxt->kbdintctxt == NULL) 16671867Smsmith authctxt->kbdintctxt = kbdint_alloc(devs); 167102550Siwasaki return auth2_challenge_start(authctxt); 16882367Smsmith} 16967754Smsmith 170114237Snjl/* unregister kbd-int callbacks and context */ 17177424Smsmithvoid 17291116Smsmithauth2_challenge_stop(Authctxt *authctxt) 17371867Smsmith{ 17471867Smsmith /* unregister callback */ 175123315Snjl dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL); 17691116Smsmith if (authctxt->kbdintctxt != NULL) { 17771867Smsmith kbdint_free(authctxt->kbdintctxt); 17880062Smsmith authctxt->kbdintctxt = NULL; 17971867Smsmith } 18067754Smsmith} 18171867Smsmith 18267754Smsmith/* side effect: sets authctxt->postponed if a reply was sent*/ 18367754Smsmithstatic int 184114237Snjlauth2_challenge_start(Authctxt *authctxt) 185107325Siwasaki{ 18667754Smsmith KbdintAuthctxt *kbdintctxt = authctxt->kbdintctxt; 18767754Smsmith 18867754Smsmith debug2("auth2_challenge_start: devices %s", 18967754Smsmith kbdintctxt->devices ? kbdintctxt->devices : "<empty>"); 19067754Smsmith 19167754Smsmith if (kbdint_next_device(kbdintctxt) == 0) { 19299146Siwasaki auth2_challenge_stop(authctxt); 19367754Smsmith return 0; 194128212Snjl } 195128212Snjl debug("auth2_challenge_start: trying authentication method '%s'", 196128212Snjl kbdintctxt->device->name); 197128212Snjl 198128212Snjl if ((kbdintctxt->ctxt = kbdintctxt->device->init_ctx(authctxt)) == NULL) { 199128212Snjl auth2_challenge_stop(authctxt); 200128212Snjl return 0; 20167754Smsmith } 202107325Siwasaki if (send_userauth_info_request(authctxt) == 0) { 20367754Smsmith auth2_challenge_stop(authctxt); 20483174Smsmith return 0; 205123315Snjl } 206117521Snjl dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, 207123315Snjl &input_userauth_info_response); 20867754Smsmith 20967754Smsmith authctxt->postponed = 1; 21067754Smsmith return 0; 21167754Smsmith} 21267754Smsmith 21367754Smsmithstatic int 21467754Smsmithsend_userauth_info_request(Authctxt *authctxt) 21567754Smsmith{ 21667754Smsmith KbdintAuthctxt *kbdintctxt; 21767754Smsmith char *name, *instr, **prompts; 21867754Smsmith int i; 21967754Smsmith u_int numprompts, *echo_on; 22067754Smsmith 22167754Smsmith kbdintctxt = authctxt->kbdintctxt; 22267754Smsmith if (kbdintctxt->device->query(kbdintctxt->ctxt, 22367754Smsmith &name, &instr, &numprompts, &prompts, &echo_on)) 22467754Smsmith return 0; 22567754Smsmith 22667754Smsmith packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST); 22767754Smsmith packet_put_cstring(name); 22867754Smsmith packet_put_cstring(instr); 229107325Siwasaki packet_put_cstring(""); /* language not used */ 23067754Smsmith packet_put_int(numprompts); 231117521Snjl for (i = 0; i < numprompts; i++) { 232123315Snjl packet_put_cstring(prompts[i]); 233117521Snjl packet_put_char(echo_on[i]); 234123315Snjl } 23567754Smsmith packet_send(); 23667754Smsmith packet_write_wait(); 23767754Smsmith 23867754Smsmith for (i = 0; i < numprompts; i++) 23967754Smsmith xfree(prompts[i]); 24067754Smsmith xfree(prompts); 24167754Smsmith xfree(echo_on); 24267754Smsmith xfree(name); 24367754Smsmith xfree(instr); 24467754Smsmith return 1; 245107325Siwasaki} 24667754Smsmith 24777424Smsmithstatic void 24867754Smsmithinput_userauth_info_response(int type, u_int32_t seq, void *ctxt) 24967754Smsmith{ 25067754Smsmith Authctxt *authctxt = ctxt; 25167754Smsmith KbdintAuthctxt *kbdintctxt; 252107325Siwasaki int i, authenticated = 0, res, len; 25367754Smsmith u_int nresp; 25467754Smsmith char **response = NULL, *method; 25567754Smsmith 25667754Smsmith if (authctxt == NULL) 25767754Smsmith fatal("input_userauth_info_response: no authctxt"); 25867754Smsmith kbdintctxt = authctxt->kbdintctxt; 25967754Smsmith if (kbdintctxt == NULL || kbdintctxt->ctxt == NULL) 26067754Smsmith fatal("input_userauth_info_response: no kbdintctxt"); 26167754Smsmith if (kbdintctxt->device == NULL) 26267754Smsmith fatal("input_userauth_info_response: no device"); 26367754Smsmith 26467754Smsmith authctxt->postponed = 0; /* reset */ 26569450Smsmith nresp = packet_get_int(); 26667754Smsmith if (nresp > 0) { 26767754Smsmith response = xmalloc(nresp * sizeof(char*)); 26867754Smsmith for (i = 0; i < nresp; i++) 26991116Smsmith response[i] = packet_get_string(NULL); 27067754Smsmith } 27167754Smsmith packet_check_eom(); 27267754Smsmith 27367754Smsmith if (authctxt->valid) { 27467754Smsmith res = kbdintctxt->device->respond(kbdintctxt->ctxt, 27567754Smsmith nresp, response); 27691116Smsmith } else { 27767754Smsmith res = -1; 27867754Smsmith } 27991116Smsmith 28067754Smsmith for (i = 0; i < nresp; i++) { 28167754Smsmith memset(response[i], 'r', strlen(response[i])); 282114237Snjl xfree(response[i]); 283107325Siwasaki } 28467754Smsmith if (response) 285107325Siwasaki xfree(response); 28667754Smsmith 287107325Siwasaki switch (res) { 288107325Siwasaki case 0: 289107325Siwasaki /* Success! */ 290107325Siwasaki authenticated = 1; 29167754Smsmith break; 292107325Siwasaki case 1: 293107325Siwasaki /* Authentication needs further interaction */ 294107325Siwasaki if (send_userauth_info_request(authctxt) == 1) 295107325Siwasaki authctxt->postponed = 1; 296107325Siwasaki break; 29767754Smsmith default: 29867754Smsmith /* Failure! */ 29967754Smsmith break; 30067754Smsmith } 30167754Smsmith 30287031Smsmith len = strlen("keyboard-interactive") + 2 + 30367754Smsmith strlen(kbdintctxt->device->name); 30467754Smsmith method = xmalloc(len); 30567754Smsmith snprintf(method, len, "keyboard-interactive/%s", 30667754Smsmith kbdintctxt->device->name); 30767754Smsmith 30867754Smsmith if (!authctxt->postponed) { 30967754Smsmith if (authenticated) { 31091116Smsmith auth2_challenge_stop(authctxt); 31187031Smsmith } else { 31291116Smsmith /* start next device */ 31387031Smsmith /* may set authctxt->postponed */ 31487031Smsmith auth2_challenge_start(authctxt); 31567754Smsmith } 31667754Smsmith } 31767754Smsmith userauth_finish(authctxt, authenticated, method); 31867754Smsmith xfree(method); 31967754Smsmith} 32067754Smsmith 32167754Smsmithvoid 32267754Smsmithprivsep_challenge_enable(void) 32367754Smsmith{ 32467754Smsmith#ifdef BSD_AUTH 32567754Smsmith extern KbdintDevice mm_bsdauth_device; 32691116Smsmith#endif 32767754Smsmith#ifdef USE_PAM 32867754Smsmith extern KbdintDevice mm_pam_device; 32967754Smsmith#endif 33067754Smsmith#ifdef SKEY 33167754Smsmith extern KbdintDevice mm_skey_device; 33267754Smsmith#endif 33367754Smsmith int n = 0; 33467754Smsmith 33567754Smsmith#ifdef BSD_AUTH 33667754Smsmith devices[n++] = &mm_bsdauth_device; 33767754Smsmith#else 33867754Smsmith#ifdef USE_PAM 33967754Smsmith devices[n++] = &mm_pam_device; 34067754Smsmith#endif 341107325Siwasaki#ifdef SKEY 342107325Siwasaki devices[n++] = &mm_skey_device; 34367754Smsmith#endif 34467754Smsmith#endif 34567754Smsmith} 34677424Smsmith