static krb5_error_code otp_client_process(krb5_context context, krb5_clpreauth_moddata moddata, krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt, krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, krb5_kdc_req *request, krb5_data *encoded_request_body, krb5_data *encoded_previous_request, krb5_pa_data *pa_data, krb5_prompter_fct prompter, void *prompter_data, krb5_pa_data ***pa_data_out) { krb5_pa_otp_challenge *chl = NULL; krb5_otp_tokeninfo *ti = NULL; krb5_keyblock *as_key = NULL; krb5_pa_otp_req *req = NULL; krb5_error_code retval = 0; krb5_data value, pin; const char *answer; if (modreq == NULL) return ENOMEM; chl = *(krb5_pa_otp_challenge **)modreq; *pa_data_out = NULL; /* Get FAST armor key. */ as_key = cb->fast_armor(context, rock); if (as_key == NULL) return ENOENT; /* Use FAST armor key as response key. */ retval = cb->set_as_key(context, rock, as_key); if (retval != 0) return retval; /* Attempt to get token selection from the responder. */ pin = empty_data(); value = empty_data(); answer = cb->get_responder_answer(context, rock, KRB5_RESPONDER_QUESTION_OTP); retval = codec_decode_answer(context, answer, chl->tokeninfo, &ti, &value, &pin); if (retval != 0) { /* If the responder doesn't have a token selection, * we need to select the token via prompting. */ retval = prompt_for_token(context, prompter, prompter_data, chl->tokeninfo, &ti, &value, &pin); if (retval != 0) goto error; } /* Make the request. */ retval = make_request(context, ti, &value, &pin, &req); if (retval != 0) goto error; /* Save information about the token which was used. */ save_config_tokeninfo(context, cb, rock, ti); /* Encrypt the challenge's nonce and set it in the request. */ retval = encrypt_nonce(context, as_key, chl, req); if (retval != 0) goto error; /* Encode the request into the pa_data output. */ retval = set_pa_data(req, pa_data_out); error: krb5_free_data_contents(context, &value); krb5_free_data_contents(context, &pin); k5_free_pa_otp_req(context, req); return retval; }