xref: /freebsd/crypto/krb5/src/plugins/preauth/otp/main.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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