1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /* plugins/preauth/otp/main.c - OTP kdcpreauth module definition */
3*7f2fe78bSCy Schubert /*
4*7f2fe78bSCy Schubert * Copyright 2011 NORDUnet A/S. All rights reserved.
5*7f2fe78bSCy Schubert * Copyright 2013 Red Hat, Inc. All rights reserved.
6*7f2fe78bSCy Schubert *
7*7f2fe78bSCy Schubert * Redistribution and use in source and binary forms, with or without
8*7f2fe78bSCy Schubert * modification, are permitted provided that the following conditions are met:
9*7f2fe78bSCy Schubert *
10*7f2fe78bSCy Schubert * 1. Redistributions of source code must retain the above copyright
11*7f2fe78bSCy Schubert * notice, this list of conditions and the following disclaimer.
12*7f2fe78bSCy Schubert *
13*7f2fe78bSCy Schubert * 2. Redistributions in binary form must reproduce the above copyright
14*7f2fe78bSCy Schubert * notice, this list of conditions and the following disclaimer in
15*7f2fe78bSCy Schubert * the documentation and/or other materials provided with the
16*7f2fe78bSCy Schubert * distribution.
17*7f2fe78bSCy Schubert *
18*7f2fe78bSCy Schubert * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
19*7f2fe78bSCy Schubert * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20*7f2fe78bSCy Schubert * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21*7f2fe78bSCy Schubert * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22*7f2fe78bSCy Schubert * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23*7f2fe78bSCy Schubert * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24*7f2fe78bSCy Schubert * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25*7f2fe78bSCy Schubert * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26*7f2fe78bSCy Schubert * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27*7f2fe78bSCy Schubert * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28*7f2fe78bSCy Schubert * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29*7f2fe78bSCy Schubert */
30*7f2fe78bSCy Schubert
31*7f2fe78bSCy Schubert #include "k5-int.h"
32*7f2fe78bSCy Schubert #include "k5-json.h"
33*7f2fe78bSCy Schubert #include <krb5/preauth_plugin.h>
34*7f2fe78bSCy Schubert #include "otp_state.h"
35*7f2fe78bSCy Schubert
36*7f2fe78bSCy Schubert #include <errno.h>
37*7f2fe78bSCy Schubert #include <ctype.h>
38*7f2fe78bSCy Schubert
39*7f2fe78bSCy Schubert static krb5_preauthtype otp_pa_type_list[] =
40*7f2fe78bSCy Schubert { KRB5_PADATA_OTP_REQUEST, 0 };
41*7f2fe78bSCy Schubert
42*7f2fe78bSCy Schubert struct request_state {
43*7f2fe78bSCy Schubert krb5_context context;
44*7f2fe78bSCy Schubert krb5_kdcpreauth_verify_respond_fn respond;
45*7f2fe78bSCy Schubert void *arg;
46*7f2fe78bSCy Schubert krb5_enc_tkt_part *enc_tkt_reply;
47*7f2fe78bSCy Schubert krb5_kdcpreauth_callbacks preauth_cb;
48*7f2fe78bSCy Schubert krb5_kdcpreauth_rock rock;
49*7f2fe78bSCy Schubert };
50*7f2fe78bSCy Schubert
51*7f2fe78bSCy Schubert static krb5_error_code
decrypt_encdata(krb5_context context,krb5_keyblock * armor_key,krb5_pa_otp_req * req,krb5_data * out)52*7f2fe78bSCy Schubert decrypt_encdata(krb5_context context, krb5_keyblock *armor_key,
53*7f2fe78bSCy Schubert krb5_pa_otp_req *req, krb5_data *out)
54*7f2fe78bSCy Schubert {
55*7f2fe78bSCy Schubert krb5_error_code retval;
56*7f2fe78bSCy Schubert krb5_data plaintext;
57*7f2fe78bSCy Schubert
58*7f2fe78bSCy Schubert if (req == NULL)
59*7f2fe78bSCy Schubert return EINVAL;
60*7f2fe78bSCy Schubert
61*7f2fe78bSCy Schubert retval = alloc_data(&plaintext, req->enc_data.ciphertext.length);
62*7f2fe78bSCy Schubert if (retval)
63*7f2fe78bSCy Schubert return retval;
64*7f2fe78bSCy Schubert
65*7f2fe78bSCy Schubert retval = krb5_c_decrypt(context, armor_key, KRB5_KEYUSAGE_PA_OTP_REQUEST,
66*7f2fe78bSCy Schubert NULL, &req->enc_data, &plaintext);
67*7f2fe78bSCy Schubert if (retval != 0) {
68*7f2fe78bSCy Schubert com_err("otp", retval, "Unable to decrypt encData in PA-OTP-REQUEST");
69*7f2fe78bSCy Schubert free(plaintext.data);
70*7f2fe78bSCy Schubert return retval;
71*7f2fe78bSCy Schubert }
72*7f2fe78bSCy Schubert
73*7f2fe78bSCy Schubert *out = plaintext;
74*7f2fe78bSCy Schubert return 0;
75*7f2fe78bSCy Schubert }
76*7f2fe78bSCy Schubert
77*7f2fe78bSCy Schubert static krb5_error_code
nonce_verify(krb5_context ctx,krb5_keyblock * armor_key,const krb5_data * nonce)78*7f2fe78bSCy Schubert nonce_verify(krb5_context ctx, krb5_keyblock *armor_key,
79*7f2fe78bSCy Schubert const krb5_data *nonce)
80*7f2fe78bSCy Schubert {
81*7f2fe78bSCy Schubert krb5_error_code retval;
82*7f2fe78bSCy Schubert krb5_timestamp ts;
83*7f2fe78bSCy Schubert krb5_data *er = NULL;
84*7f2fe78bSCy Schubert
85*7f2fe78bSCy Schubert if (armor_key == NULL || nonce->data == NULL) {
86*7f2fe78bSCy Schubert retval = EINVAL;
87*7f2fe78bSCy Schubert goto out;
88*7f2fe78bSCy Schubert }
89*7f2fe78bSCy Schubert
90*7f2fe78bSCy Schubert /* Decode the PA-OTP-ENC-REQUEST structure. */
91*7f2fe78bSCy Schubert retval = decode_krb5_pa_otp_enc_req(nonce, &er);
92*7f2fe78bSCy Schubert if (retval != 0)
93*7f2fe78bSCy Schubert goto out;
94*7f2fe78bSCy Schubert
95*7f2fe78bSCy Schubert /* Make sure the nonce is exactly the same size as the one generated. */
96*7f2fe78bSCy Schubert if (er->length != armor_key->length + sizeof(krb5_timestamp))
97*7f2fe78bSCy Schubert goto out;
98*7f2fe78bSCy Schubert
99*7f2fe78bSCy Schubert /* Check to make sure the timestamp at the beginning is still valid. */
100*7f2fe78bSCy Schubert ts = load_32_be(er->data);
101*7f2fe78bSCy Schubert retval = krb5_check_clockskew(ctx, ts);
102*7f2fe78bSCy Schubert
103*7f2fe78bSCy Schubert out:
104*7f2fe78bSCy Schubert krb5_free_data(ctx, er);
105*7f2fe78bSCy Schubert return retval;
106*7f2fe78bSCy Schubert }
107*7f2fe78bSCy Schubert
108*7f2fe78bSCy Schubert static krb5_error_code
timestamp_verify(krb5_context ctx,const krb5_data * nonce)109*7f2fe78bSCy Schubert timestamp_verify(krb5_context ctx, const krb5_data *nonce)
110*7f2fe78bSCy Schubert {
111*7f2fe78bSCy Schubert krb5_error_code retval = EINVAL;
112*7f2fe78bSCy Schubert krb5_pa_enc_ts *et = NULL;
113*7f2fe78bSCy Schubert
114*7f2fe78bSCy Schubert if (nonce->data == NULL)
115*7f2fe78bSCy Schubert goto out;
116*7f2fe78bSCy Schubert
117*7f2fe78bSCy Schubert /* Decode the PA-ENC-TS-ENC structure. */
118*7f2fe78bSCy Schubert retval = decode_krb5_pa_enc_ts(nonce, &et);
119*7f2fe78bSCy Schubert if (retval != 0)
120*7f2fe78bSCy Schubert goto out;
121*7f2fe78bSCy Schubert
122*7f2fe78bSCy Schubert /* Check the clockskew. */
123*7f2fe78bSCy Schubert retval = krb5_check_clockskew(ctx, et->patimestamp);
124*7f2fe78bSCy Schubert
125*7f2fe78bSCy Schubert out:
126*7f2fe78bSCy Schubert krb5_free_pa_enc_ts(ctx, et);
127*7f2fe78bSCy Schubert return retval;
128*7f2fe78bSCy Schubert }
129*7f2fe78bSCy Schubert
130*7f2fe78bSCy Schubert static krb5_error_code
nonce_generate(krb5_context ctx,unsigned int length,krb5_data * nonce_out)131*7f2fe78bSCy Schubert nonce_generate(krb5_context ctx, unsigned int length, krb5_data *nonce_out)
132*7f2fe78bSCy Schubert {
133*7f2fe78bSCy Schubert krb5_data nonce;
134*7f2fe78bSCy Schubert krb5_error_code retval;
135*7f2fe78bSCy Schubert krb5_timestamp now;
136*7f2fe78bSCy Schubert
137*7f2fe78bSCy Schubert retval = krb5_timeofday(ctx, &now);
138*7f2fe78bSCy Schubert if (retval != 0)
139*7f2fe78bSCy Schubert return retval;
140*7f2fe78bSCy Schubert
141*7f2fe78bSCy Schubert retval = alloc_data(&nonce, sizeof(now) + length);
142*7f2fe78bSCy Schubert if (retval != 0)
143*7f2fe78bSCy Schubert return retval;
144*7f2fe78bSCy Schubert
145*7f2fe78bSCy Schubert retval = krb5_c_random_make_octets(ctx, &nonce);
146*7f2fe78bSCy Schubert if (retval != 0) {
147*7f2fe78bSCy Schubert free(nonce.data);
148*7f2fe78bSCy Schubert return retval;
149*7f2fe78bSCy Schubert }
150*7f2fe78bSCy Schubert
151*7f2fe78bSCy Schubert store_32_be(now, nonce.data);
152*7f2fe78bSCy Schubert *nonce_out = nonce;
153*7f2fe78bSCy Schubert return 0;
154*7f2fe78bSCy Schubert }
155*7f2fe78bSCy Schubert
156*7f2fe78bSCy Schubert static void
on_response(void * data,krb5_error_code retval,otp_response response,char * const * indicators)157*7f2fe78bSCy Schubert on_response(void *data, krb5_error_code retval, otp_response response,
158*7f2fe78bSCy Schubert char *const *indicators)
159*7f2fe78bSCy Schubert {
160*7f2fe78bSCy Schubert struct request_state rs = *(struct request_state *)data;
161*7f2fe78bSCy Schubert krb5_context context = rs.context;
162*7f2fe78bSCy Schubert krb5_keyblock *armor_key;
163*7f2fe78bSCy Schubert char *const *ind;
164*7f2fe78bSCy Schubert
165*7f2fe78bSCy Schubert free(data);
166*7f2fe78bSCy Schubert
167*7f2fe78bSCy Schubert if (retval == 0 && response != otp_response_success)
168*7f2fe78bSCy Schubert retval = KRB5_PREAUTH_FAILED;
169*7f2fe78bSCy Schubert if (retval)
170*7f2fe78bSCy Schubert goto done;
171*7f2fe78bSCy Schubert
172*7f2fe78bSCy Schubert rs.enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
173*7f2fe78bSCy Schubert armor_key = rs.preauth_cb->fast_armor(context, rs.rock);
174*7f2fe78bSCy Schubert if (armor_key == NULL) {
175*7f2fe78bSCy Schubert retval = ENOENT;
176*7f2fe78bSCy Schubert goto done;
177*7f2fe78bSCy Schubert }
178*7f2fe78bSCy Schubert
179*7f2fe78bSCy Schubert retval = rs.preauth_cb->replace_reply_key(context, rs.rock, armor_key,
180*7f2fe78bSCy Schubert FALSE);
181*7f2fe78bSCy Schubert if (retval)
182*7f2fe78bSCy Schubert goto done;
183*7f2fe78bSCy Schubert
184*7f2fe78bSCy Schubert for (ind = indicators; ind != NULL && *ind != NULL; ind++) {
185*7f2fe78bSCy Schubert retval = rs.preauth_cb->add_auth_indicator(context, rs.rock, *ind);
186*7f2fe78bSCy Schubert if (retval)
187*7f2fe78bSCy Schubert goto done;
188*7f2fe78bSCy Schubert }
189*7f2fe78bSCy Schubert
190*7f2fe78bSCy Schubert done:
191*7f2fe78bSCy Schubert rs.respond(rs.arg, retval, NULL, NULL, NULL);
192*7f2fe78bSCy Schubert }
193*7f2fe78bSCy Schubert
194*7f2fe78bSCy Schubert static krb5_error_code
otp_init(krb5_context context,krb5_kdcpreauth_moddata * moddata_out,const char ** realmnames)195*7f2fe78bSCy Schubert otp_init(krb5_context context, krb5_kdcpreauth_moddata *moddata_out,
196*7f2fe78bSCy Schubert const char **realmnames)
197*7f2fe78bSCy Schubert {
198*7f2fe78bSCy Schubert krb5_error_code retval;
199*7f2fe78bSCy Schubert otp_state *state;
200*7f2fe78bSCy Schubert
201*7f2fe78bSCy Schubert retval = otp_state_new(context, &state);
202*7f2fe78bSCy Schubert if (retval)
203*7f2fe78bSCy Schubert return retval;
204*7f2fe78bSCy Schubert *moddata_out = (krb5_kdcpreauth_moddata)state;
205*7f2fe78bSCy Schubert return 0;
206*7f2fe78bSCy Schubert }
207*7f2fe78bSCy Schubert
208*7f2fe78bSCy Schubert static void
otp_fini(krb5_context context,krb5_kdcpreauth_moddata moddata)209*7f2fe78bSCy Schubert otp_fini(krb5_context context, krb5_kdcpreauth_moddata moddata)
210*7f2fe78bSCy Schubert {
211*7f2fe78bSCy Schubert otp_state_free((otp_state *)moddata);
212*7f2fe78bSCy Schubert }
213*7f2fe78bSCy Schubert
214*7f2fe78bSCy Schubert static int
otp_flags(krb5_context context,krb5_preauthtype pa_type)215*7f2fe78bSCy Schubert otp_flags(krb5_context context, krb5_preauthtype pa_type)
216*7f2fe78bSCy Schubert {
217*7f2fe78bSCy Schubert return PA_REPLACES_KEY;
218*7f2fe78bSCy Schubert }
219*7f2fe78bSCy Schubert
220*7f2fe78bSCy Schubert static void
otp_edata(krb5_context context,krb5_kdc_req * request,krb5_kdcpreauth_callbacks cb,krb5_kdcpreauth_rock rock,krb5_kdcpreauth_moddata moddata,krb5_preauthtype pa_type,krb5_kdcpreauth_edata_respond_fn respond,void * arg)221*7f2fe78bSCy Schubert otp_edata(krb5_context context, krb5_kdc_req *request,
222*7f2fe78bSCy Schubert krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
223*7f2fe78bSCy Schubert krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type,
224*7f2fe78bSCy Schubert krb5_kdcpreauth_edata_respond_fn respond, void *arg)
225*7f2fe78bSCy Schubert {
226*7f2fe78bSCy Schubert krb5_otp_tokeninfo ti, *tis[2] = { &ti, NULL };
227*7f2fe78bSCy Schubert krb5_keyblock *armor_key = NULL;
228*7f2fe78bSCy Schubert krb5_pa_otp_challenge chl;
229*7f2fe78bSCy Schubert krb5_pa_data *pa = NULL;
230*7f2fe78bSCy Schubert krb5_error_code retval;
231*7f2fe78bSCy Schubert krb5_data *encoding, nonce = empty_data();
232*7f2fe78bSCy Schubert char *config;
233*7f2fe78bSCy Schubert
234*7f2fe78bSCy Schubert /* Determine if otp is enabled for the user. */
235*7f2fe78bSCy Schubert retval = cb->get_string(context, rock, "otp", &config);
236*7f2fe78bSCy Schubert if (retval == 0 && config == NULL)
237*7f2fe78bSCy Schubert retval = ENOENT;
238*7f2fe78bSCy Schubert if (retval != 0)
239*7f2fe78bSCy Schubert goto out;
240*7f2fe78bSCy Schubert cb->free_string(context, rock, config);
241*7f2fe78bSCy Schubert
242*7f2fe78bSCy Schubert /* Get the armor key. This indicates the length of random data to use in
243*7f2fe78bSCy Schubert * the nonce. */
244*7f2fe78bSCy Schubert armor_key = cb->fast_armor(context, rock);
245*7f2fe78bSCy Schubert if (armor_key == NULL) {
246*7f2fe78bSCy Schubert retval = ENOENT;
247*7f2fe78bSCy Schubert goto out;
248*7f2fe78bSCy Schubert }
249*7f2fe78bSCy Schubert
250*7f2fe78bSCy Schubert /* Build the (mostly empty) challenge. */
251*7f2fe78bSCy Schubert memset(&ti, 0, sizeof(ti));
252*7f2fe78bSCy Schubert memset(&chl, 0, sizeof(chl));
253*7f2fe78bSCy Schubert chl.tokeninfo = tis;
254*7f2fe78bSCy Schubert ti.format = -1;
255*7f2fe78bSCy Schubert ti.length = -1;
256*7f2fe78bSCy Schubert ti.iteration_count = -1;
257*7f2fe78bSCy Schubert
258*7f2fe78bSCy Schubert /* Generate the nonce. */
259*7f2fe78bSCy Schubert retval = nonce_generate(context, armor_key->length, &nonce);
260*7f2fe78bSCy Schubert if (retval != 0)
261*7f2fe78bSCy Schubert goto out;
262*7f2fe78bSCy Schubert chl.nonce = nonce;
263*7f2fe78bSCy Schubert
264*7f2fe78bSCy Schubert /* Build the output pa-data. */
265*7f2fe78bSCy Schubert retval = encode_krb5_pa_otp_challenge(&chl, &encoding);
266*7f2fe78bSCy Schubert if (retval != 0)
267*7f2fe78bSCy Schubert goto out;
268*7f2fe78bSCy Schubert pa = k5alloc(sizeof(krb5_pa_data), &retval);
269*7f2fe78bSCy Schubert if (pa == NULL) {
270*7f2fe78bSCy Schubert krb5_free_data(context, encoding);
271*7f2fe78bSCy Schubert goto out;
272*7f2fe78bSCy Schubert }
273*7f2fe78bSCy Schubert pa->pa_type = KRB5_PADATA_OTP_CHALLENGE;
274*7f2fe78bSCy Schubert pa->contents = (krb5_octet *)encoding->data;
275*7f2fe78bSCy Schubert pa->length = encoding->length;
276*7f2fe78bSCy Schubert free(encoding);
277*7f2fe78bSCy Schubert
278*7f2fe78bSCy Schubert out:
279*7f2fe78bSCy Schubert krb5_free_data_contents(context, &nonce);
280*7f2fe78bSCy Schubert (*respond)(arg, retval, pa);
281*7f2fe78bSCy Schubert }
282*7f2fe78bSCy Schubert
283*7f2fe78bSCy Schubert static void
otp_verify(krb5_context context,krb5_data * req_pkt,krb5_kdc_req * request,krb5_enc_tkt_part * enc_tkt_reply,krb5_pa_data * pa,krb5_kdcpreauth_callbacks cb,krb5_kdcpreauth_rock rock,krb5_kdcpreauth_moddata moddata,krb5_kdcpreauth_verify_respond_fn respond,void * arg)284*7f2fe78bSCy Schubert otp_verify(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request,
285*7f2fe78bSCy Schubert krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *pa,
286*7f2fe78bSCy Schubert krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
287*7f2fe78bSCy Schubert krb5_kdcpreauth_moddata moddata,
288*7f2fe78bSCy Schubert krb5_kdcpreauth_verify_respond_fn respond, void *arg)
289*7f2fe78bSCy Schubert {
290*7f2fe78bSCy Schubert krb5_keyblock *armor_key = NULL;
291*7f2fe78bSCy Schubert krb5_pa_otp_req *req = NULL;
292*7f2fe78bSCy Schubert struct request_state *rs;
293*7f2fe78bSCy Schubert krb5_error_code retval;
294*7f2fe78bSCy Schubert krb5_data d, plaintext;
295*7f2fe78bSCy Schubert char *config;
296*7f2fe78bSCy Schubert
297*7f2fe78bSCy Schubert /* Get the FAST armor key. */
298*7f2fe78bSCy Schubert armor_key = cb->fast_armor(context, rock);
299*7f2fe78bSCy Schubert if (armor_key == NULL) {
300*7f2fe78bSCy Schubert retval = KRB5KDC_ERR_PREAUTH_FAILED;
301*7f2fe78bSCy Schubert com_err("otp", retval, "No armor key found when verifying padata");
302*7f2fe78bSCy Schubert goto error;
303*7f2fe78bSCy Schubert }
304*7f2fe78bSCy Schubert
305*7f2fe78bSCy Schubert /* Decode the request. */
306*7f2fe78bSCy Schubert d = make_data(pa->contents, pa->length);
307*7f2fe78bSCy Schubert retval = decode_krb5_pa_otp_req(&d, &req);
308*7f2fe78bSCy Schubert if (retval != 0) {
309*7f2fe78bSCy Schubert com_err("otp", retval, "Unable to decode OTP request");
310*7f2fe78bSCy Schubert goto error;
311*7f2fe78bSCy Schubert }
312*7f2fe78bSCy Schubert
313*7f2fe78bSCy Schubert /* Decrypt the nonce from the request. */
314*7f2fe78bSCy Schubert retval = decrypt_encdata(context, armor_key, req, &plaintext);
315*7f2fe78bSCy Schubert if (retval != 0) {
316*7f2fe78bSCy Schubert com_err("otp", retval, "Unable to decrypt nonce");
317*7f2fe78bSCy Schubert goto error;
318*7f2fe78bSCy Schubert }
319*7f2fe78bSCy Schubert
320*7f2fe78bSCy Schubert /* Verify the nonce or timestamp. */
321*7f2fe78bSCy Schubert retval = nonce_verify(context, armor_key, &plaintext);
322*7f2fe78bSCy Schubert if (retval != 0)
323*7f2fe78bSCy Schubert retval = timestamp_verify(context, &plaintext);
324*7f2fe78bSCy Schubert krb5_free_data_contents(context, &plaintext);
325*7f2fe78bSCy Schubert if (retval != 0) {
326*7f2fe78bSCy Schubert com_err("otp", retval, "Unable to verify nonce or timestamp");
327*7f2fe78bSCy Schubert goto error;
328*7f2fe78bSCy Schubert }
329*7f2fe78bSCy Schubert
330*7f2fe78bSCy Schubert /* Create the request state. Save the response callback, and the
331*7f2fe78bSCy Schubert * enc_tkt_reply pointer so we can set the TKT_FLG_PRE_AUTH flag later. */
332*7f2fe78bSCy Schubert rs = k5alloc(sizeof(struct request_state), &retval);
333*7f2fe78bSCy Schubert if (rs == NULL)
334*7f2fe78bSCy Schubert goto error;
335*7f2fe78bSCy Schubert rs->context = context;
336*7f2fe78bSCy Schubert rs->arg = arg;
337*7f2fe78bSCy Schubert rs->respond = respond;
338*7f2fe78bSCy Schubert rs->enc_tkt_reply = enc_tkt_reply;
339*7f2fe78bSCy Schubert rs->preauth_cb = cb;
340*7f2fe78bSCy Schubert rs->rock = rock;
341*7f2fe78bSCy Schubert
342*7f2fe78bSCy Schubert /* Get the principal's OTP configuration string. */
343*7f2fe78bSCy Schubert retval = cb->get_string(context, rock, "otp", &config);
344*7f2fe78bSCy Schubert if (retval == 0 && config == NULL)
345*7f2fe78bSCy Schubert retval = KRB5_PREAUTH_FAILED;
346*7f2fe78bSCy Schubert if (retval != 0) {
347*7f2fe78bSCy Schubert free(rs);
348*7f2fe78bSCy Schubert goto error;
349*7f2fe78bSCy Schubert }
350*7f2fe78bSCy Schubert
351*7f2fe78bSCy Schubert /* Send the request. */
352*7f2fe78bSCy Schubert otp_state_verify((otp_state *)moddata, cb->event_context(context, rock),
353*7f2fe78bSCy Schubert cb->client_name(context, rock), config, req, on_response,
354*7f2fe78bSCy Schubert rs);
355*7f2fe78bSCy Schubert cb->free_string(context, rock, config);
356*7f2fe78bSCy Schubert
357*7f2fe78bSCy Schubert k5_free_pa_otp_req(context, req);
358*7f2fe78bSCy Schubert return;
359*7f2fe78bSCy Schubert
360*7f2fe78bSCy Schubert error:
361*7f2fe78bSCy Schubert k5_free_pa_otp_req(context, req);
362*7f2fe78bSCy Schubert (*respond)(arg, retval, NULL, NULL, NULL);
363*7f2fe78bSCy Schubert }
364*7f2fe78bSCy Schubert
365*7f2fe78bSCy Schubert krb5_error_code
366*7f2fe78bSCy Schubert kdcpreauth_otp_initvt(krb5_context context, int maj_ver, int min_ver,
367*7f2fe78bSCy Schubert krb5_plugin_vtable vtable);
368*7f2fe78bSCy Schubert
369*7f2fe78bSCy Schubert krb5_error_code
kdcpreauth_otp_initvt(krb5_context context,int maj_ver,int min_ver,krb5_plugin_vtable vtable)370*7f2fe78bSCy Schubert kdcpreauth_otp_initvt(krb5_context context, int maj_ver, int min_ver,
371*7f2fe78bSCy Schubert krb5_plugin_vtable vtable)
372*7f2fe78bSCy Schubert {
373*7f2fe78bSCy Schubert krb5_kdcpreauth_vtable vt;
374*7f2fe78bSCy Schubert
375*7f2fe78bSCy Schubert if (maj_ver != 1)
376*7f2fe78bSCy Schubert return KRB5_PLUGIN_VER_NOTSUPP;
377*7f2fe78bSCy Schubert
378*7f2fe78bSCy Schubert vt = (krb5_kdcpreauth_vtable)vtable;
379*7f2fe78bSCy Schubert vt->name = "otp";
380*7f2fe78bSCy Schubert vt->pa_type_list = otp_pa_type_list;
381*7f2fe78bSCy Schubert vt->init = otp_init;
382*7f2fe78bSCy Schubert vt->fini = otp_fini;
383*7f2fe78bSCy Schubert vt->flags = otp_flags;
384*7f2fe78bSCy Schubert vt->edata = otp_edata;
385*7f2fe78bSCy Schubert vt->verify = otp_verify;
386*7f2fe78bSCy Schubert
387*7f2fe78bSCy Schubert com_err("otp", 0, "Loaded");
388*7f2fe78bSCy Schubert
389*7f2fe78bSCy Schubert return 0;
390*7f2fe78bSCy Schubert }
391