auth-chall.c revision 181104
155714Skris/* $OpenBSD: auth-chall.c,v 1.12 2006/08/03 03:34:41 deraadt Exp $ */
255714Skris/*
355714Skris * Copyright (c) 2001 Markus Friedl.  All rights reserved.
455714Skris *
555714Skris * Redistribution and use in source and binary forms, with or without
655714Skris * modification, are permitted provided that the following conditions
755714Skris * are met:
8280304Sjkim * 1. Redistributions of source code must retain the above copyright
955714Skris *    notice, this list of conditions and the following disclaimer.
1055714Skris * 2. Redistributions in binary form must reproduce the above copyright
1155714Skris *    notice, this list of conditions and the following disclaimer in the
1255714Skris *    documentation and/or other materials provided with the distribution.
1355714Skris *
1455714Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15280304Sjkim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1655714Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1755714Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1855714Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1955714Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2055714Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2155714Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22280304Sjkim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2355714Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2455714Skris */
2555714Skris
2655714Skris#include "includes.h"
2755714Skris
2855714Skris#include <sys/types.h>
2955714Skris
3055714Skris#include <stdarg.h>
3155714Skris
3255714Skris#include "xmalloc.h"
3355714Skris#include "key.h"
3455714Skris#include "hostfile.h"
3555714Skris#include "auth.h"
3655714Skris#include "log.h"
37280304Sjkim#include "servconf.h"
3855714Skris
3955714Skris/* limited protocol v1 interface to kbd-interactive authentication */
40280304Sjkim
4155714Skrisextern KbdintDevice *devices[];
4255714Skrisstatic KbdintDevice *device;
4355714Skrisextern ServerOptions options;
4455714Skris
4555714Skrischar *
4655714Skrisget_challenge(Authctxt *authctxt)
4755714Skris{
4855714Skris	char *challenge, *name, *info, **prompts;
4955714Skris	u_int i, numprompts;
5055714Skris	u_int *echo_on;
5155714Skris
52280304Sjkim#ifdef USE_PAM
5355714Skris	if (!options.use_pam)
5455714Skris		remove_kbdint_device("pam");
5555714Skris#endif
5655714Skris
5755714Skris	device = devices[0]; /* we always use the 1st device for protocol 1 */
5855714Skris	if (device == NULL)
59280304Sjkim		return NULL;
60280304Sjkim	if ((authctxt->kbdintctxt = device->init_ctx(authctxt)) == NULL)
61280304Sjkim		return NULL;
62280304Sjkim	if (device->query(authctxt->kbdintctxt, &name, &info,
63280304Sjkim	    &numprompts, &prompts, &echo_on)) {
64280304Sjkim		device->free_ctx(authctxt->kbdintctxt);
65280304Sjkim		authctxt->kbdintctxt = NULL;
66280304Sjkim		return NULL;
67280304Sjkim	}
68280304Sjkim	if (numprompts < 1)
69280304Sjkim		fatal("get_challenge: numprompts < 1");
70280304Sjkim	challenge = xstrdup(prompts[0]);
71280304Sjkim	for (i = 0; i < numprompts; i++)
72280304Sjkim		xfree(prompts[i]);
73280304Sjkim	xfree(prompts);
74280304Sjkim	xfree(name);
75280304Sjkim	xfree(echo_on);
76280304Sjkim	xfree(info);
77280304Sjkim
78280304Sjkim	return (challenge);
79280304Sjkim}
80280304Sjkimint
81280304Sjkimverify_response(Authctxt *authctxt, const char *response)
82280304Sjkim{
83280304Sjkim	char *resp[1], *name, *info, **prompts;
84280304Sjkim	u_int i, numprompts, *echo_on;
85280304Sjkim	int authenticated = 0;
86280304Sjkim
87280304Sjkim	if (device == NULL)
88280304Sjkim		return 0;
89280304Sjkim	if (authctxt->kbdintctxt == NULL)
90280304Sjkim		return 0;
91280304Sjkim	resp[0] = (char *)response;
92280304Sjkim	switch (device->respond(authctxt->kbdintctxt, 1, resp)) {
93280304Sjkim	case 0: /* Success */
94280304Sjkim		authenticated = 1;
95280304Sjkim		break;
96280304Sjkim	case 1: /* Postponed - retry with empty query for PAM */
97280304Sjkim		if ((device->query(authctxt->kbdintctxt, &name, &info,
98280304Sjkim		    &numprompts, &prompts, &echo_on)) != 0)
99280304Sjkim			break;
100280304Sjkim		if (numprompts == 0 &&
101280304Sjkim		    device->respond(authctxt->kbdintctxt, 0, resp) == 0)
102280304Sjkim			authenticated = 1;
103280304Sjkim
104280304Sjkim		for (i = 0; i < numprompts; i++)
105280304Sjkim			xfree(prompts[i]);
106280304Sjkim		xfree(prompts);
107280304Sjkim		xfree(name);
108280304Sjkim		xfree(echo_on);
109280304Sjkim		xfree(info);
110280304Sjkim		break;
111280304Sjkim	}
112280304Sjkim	device->free_ctx(authctxt->kbdintctxt);
113280304Sjkim	authctxt->kbdintctxt = NULL;
114280304Sjkim	return authenticated;
115280304Sjkim}
116280304Sjkimvoid
117280304Sjkimabandon_challenge_response(Authctxt *authctxt)
118280304Sjkim{
119280304Sjkim	if (authctxt->kbdintctxt != NULL) {
120280304Sjkim		device->free_ctx(authctxt->kbdintctxt);
121280304Sjkim		authctxt->kbdintctxt = NULL;
122280304Sjkim	}
123280304Sjkim}
124280304Sjkim